Повний огляд REST: нюанси, поради, приклади

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

Привіт, я Senior Java Developer Валентин Вівчарик i сьогодні хочу зачепити доволі обширну та важливу тему, а саме — REST. Я детально розповім про нюанси роботи з REST та дам поради щодо взаємодії з ним.

REST (REpresentational State Transfer) — це архітектурний стиль для розподілених гіпермедійних систем, який Рой Філдінг вперше представив у 2000 році в своїй знаменитій дисертації. З того часу він став одним із найбільш широко використовуваних підходів для створення вебінтерфейсів API (інтерфейсів прикладного програмування).

REST — це не протокол чи стандарт, це архітектурний стиль, а точніше — один з наявних типів синхронної комунікації вебсервісів. На етапі розробки розробники API можуть реалізувати REST різними способами.

Як і інші архітектурні стилі, REST також має свої керівні принципи та обмеження. Ці принципи мають бути дотримані, якщо інтерфейс служби має називатися RESTful.

Принципи REST

Ресурси

Ресурси у контексті REST представляють будь-який об’єкт або дані, з якими взаємодіє клієнт через сервер. Ресурс може бути будь-чим: користувач, файл, замовлення, продукт тощо. У REST API ресурси ідентифікуються через унікальні URL-адреси (Uniform Resource Locator), тобто звичні нам посилання.

Сам REST запит складається з таких частин:

  • Метод HTTP.
  • Посилання.
  • Заголовки.
  • Параметри запиту.
  • Тіло запиту.
  • Змінні шляху.
  • Версія HTTP.

А REST відповідь в свою чергу містить:

  • Статус код.
  • Заголовки.
  • Тіло відповіді (необовʼязково).
  • Версія HTTP.

Посилання

URL (уніфікований локатор ресурсу) є унікальним ідентифікатором ресурсу в REST API. Він слугує як шлях до конкретного ресурсу або його колекції. Наприклад:

  • /users — колекція всіх користувачів.
  • /users/123 — конкретний користувач із ідентифікатором 123.

URL має бути інтуїтивно зрозумілим і відображати структуру та ієрархію ресурсів. При цьому важливо дотримуватися таких принципів:

1. Використання іменників

  • URL повинен представляти ресурс, тому використовуйте іменники в множині для позначення колекцій ресурсів, наприклад:
    • GET /users — отримати список користувачів.
    • POST /users — створити нового користувача.
    • GET /users/123 — отримати інформацію про конкретного користувача з ID 123.

2. Уникання дієслів

  • Операції визначаються HTTP-методами, тому не варто використовувати дієслова в URL:
    • Правильно: GET /users, DELETE /users/123.
    • Неправильно: /getUsers, /deleteUser/123.

3. Використання ресурсів у множині

  • Використовуйте множину для позначення колекцій ресурсів:
    • GET /orders — отримати всі замовлення.
    • POST /orders — створити нове замовлення.

4. Вкладені ресурси

  • Якщо ресурс має підресурс, можна використовувати вкладені URL:
    • GET /users/123/orders — отримати всі замовлення користувача з ID 123.

5. Використання Параметрів шляху для конкретних ресурсів

  • Використовуйте Параметри шляху для конкретних ресурсів або ідентифікаторів:
    • GET /products/45 — отримати інформацію про товар з ID 45.
    • PUT /products/45 — оновити інформацію про товар.

6. Використання Параметрів запиту для фільтрації та сортування

  • Для фільтрації, сортування або інших уточнень використовуйте Параметри запиту:
    • GET /users?age=30&status=active — отримати всіх користувачів віком 30 років зі статусом «active».
    • GET /products?category=books&sort=price — отримати книги, відсортовані за ціною.

7. Уникання великих літер та спеціальних символів

  • URL має бути написаний у нижньому регістрі та не містити спеціальних символів (окрім — для розділення слів):
    • Правильно: /users, /products/45.
    • Неправильно: /Users, /Get_Products.

8. Версіонування API через URL або заголовки

  • Додавайте версію API в URL або заголовки для підтримки кількох версій:
    • GET /v1/users — для версії 1 API.
    • Або через заголовок: Accept: application/vnd.myapi.v1+json.

Параметри запиту чи Параметри шляху

У REST API є два типи параметрів для взаємодії з ресурсами: Path Parameters (параметри шляху) та Query Parameters (параметри запиту).

  • Параметри шляху — використовуються для чіткого ідентифікатора ресурсу, який знаходиться безпосередньо у URL. Це обов’язкові параметри. Наприклад:
    • /users/123 — тут 123 є параметром шляху, що вказує на конкретного користувача з ID 123.
  • Параметри запиту — використовуються для передачі додаткових умов або фільтрів для запитів. Вони додаються після символу ? і не є обов’язковими. Наприклад:
    • /users?age=30&status=active — цей запит поверне всіх користувачів, у яких вік 30 і статус активний.

Заголовки

HTTP Headers (заголовки) використовуються для передачі додаткової інформації між клієнтом і сервером.

Наприклад, популярні заголовки запиту:
  • Accept — вказує формати даних, які клієнт може приймати у відповіді (application/json, application/xml тощо).
  • Authorization — передає дані для автентифікації клієнта. Зазвичай використовується для передачі токенів доступу, наприклад, Bearer <token> у JWT або OAuth.
  • Content-Type — вказує формат даних, що передаються у запиті (application/json, application/xml тощо).
  • Cache-Control — управляє політикою кешування запитів. Наприклад, no-cache, max-age=3600.
  • User-Agent — ідентифікує клієнтське програмне забезпечення, яке виконує запит. Це може бути корисним для відстеження запитів від різних клієнтів або версій додатків.
  • Accept-Language — вказує, якою мовою або для якого регіону клієнт очікує отримати відповідь. Наприклад, en-US для англійської мови в США або uk-UA для української мови в Україні.
  • Referer — вказує на URL сторінки, з якої було надіслано запит. Корисний для аналітики та безпеки, зокрема, для захисту від атак типу CSRF.
  • If-Modified-Since — вказує дату останньої модифікації ресурсу, яку клієнт знає. Якщо ресурс не змінювався з того часу, сервер може повернути 304 Not Modified.
  • If-None-Match — використовується разом з ETag для перевірки, чи змінився ресурс. Якщо ресурс не змінився, сервер повертає 304 Not Modified.
  • X-Requested-With — використовується для вказання типу запиту (часто XMLHttpRequest для AJAX-запитів). Це може бути корисно для визначення, запит виконаний через браузер чи інший клієнт.
  • Accept-Encoding — вказує формати кодування, які клієнт може приймати. Наприклад, gzip, deflate.
  • Access-Control-Allow-Credentials — використовується в CORS для дозволу відправлення автентифікаційних даних (кукі, токени) разом із крос-доменними запитами.
  • Content-Disposition — визначає спосіб обробки контенту. Наприклад, вкладення файлів.
  • Content-Security-Policy — забезпечує політику безпеки для обмеження завантаження несанкціонованих скриптів чи контенту.
  • Expect — вказує специфічні вимоги клієнта до сервера перед відправленням повного запиту. Наприклад, 100-continue.
  • Forwarded / X-Forwarded-For — вказує IP-адресу клієнта або проміжних проксі, якщо запит проходив через них.
  • If-Unmodified-Since — дозволяє операцію тільки якщо ресурс не змінювався після вказаної дати.
Популярні заголовки відповідей:
  • Content-Type — вказує формат даних, які сервер повертає у відповіді. Наприклад, application/json.
  • Cache-Control — вказує правила кешування відповіді, як-то максимальний час кешування або заборону кешування.
  • Expires — вказує час, після якого відповідь вважається застарілою.
  • ETag — унікальний ідентифікатор версії ресурсу, який допомагає кешуванню та зменшенню навантаження на сервер шляхом повернення лише змінених даних.
  • Location — використовується для перенаправлення після успішної операції, наприклад, після створення нового ресурсу (201 Created).
  • Retry-After — вказує, через скільки секунд клієнт може повторити запит (або дату). Це часто використовується разом із кодом 429 Too Many Requests.
  • X-RateLimit-Limit — вказує максимальну кількість запитів, яку клієнт може зробити протягом певного періоду.
  • X-RateLimit-Remaining — вказує, скільки запитів залишилося до досягнення ліміту.
  • X-RateLimit-Reset — вказує час, коли ліміт на кількість запитів буде скинутий.
  • Access-Control-Allow-Origin — визначає, з яких доменів дозволено крос-доменний доступ до API (CORS).
  • Access-Control-Allow-Methods — вказує, які HTTP-методи дозволено для крос-доменного доступу.
  • Access-Control-Allow-Headers — вказує, які заголовки можуть використовуватися у крос-доменних запитах.
  • Strict-Transport-Security — примушує клієнтів використовувати лише HTTPS для підключення до сервера.
  • TE (Transfer-Encoding) — вказує, які методи кодування передачі можуть використовуватися. Наприклад, chunked.
  • Vary — вказує, які заголовки запиту можуть впливати на кешування відповіді. Наприклад, Accept-Encoding.
  • WWW-Authenticate — визначає, який метод аутентифікації використовується для захищеного ресурсу.
  • X-Content-Type-Options — захищає від спроб браузера вгадати MIME-тип контенту. Корисно для безпеки.
  • X-Frame-Options — захищає від атак типу «clickjacking», забороняючи відображення сторінки у фреймах інших сайтів.
  • X-XSS-Protection — вмикає захист від атак типу Cross-Site Scripting (XSS) у браузерах.
  • Link — надає засоби для серіалізації одного або кількох посилань у заголовках HTTP. Цей заголовок має таку саму семантику, як елемент HTML <link>. Перевага використання заголовка Link полягає в тому, що браузер може почати попереднє підключення або завантаження ресурсів до того, як сам HTML буде отримано та оброблено.

Заголовки допомагають точно налаштувати взаємодію між клієнтом і сервером, передаючи метадані, що допомагають інтерпретувати запити та відповіді.

Методи HTTP

У REST використовуються HTTP-методи для визначення дій, які виконуються над ресурсами:

  • GET — отримати дані ресурсу.
  • POST — створити новий ресурс.
  • PUT — повністю оновити ресурс або створити новий, якщо його не існує.
  • PATCH — частково оновити ресурс.
  • DELETE — видалити ресурс.
  • HEAD — отримати метадані ресурсу (тіло відповіді не повертається).
  • OPTIONS — запитує, які методи підтримуються для ресурсу.
  • CONNECT — створює тунель до сервера для двонаправленої комунікації.
  • TRACE — діагностичний метод, який повертає вихідний запит для тестування маршруту.

Вибір методу залежить від операції, яку потрібно виконати над ресурсом. Методи також визначають, чи є операція безпечною та ідемпотентною (поясню трохи пізніше).

Типи даних

Дані, які передаються між клієнтом і сервером у REST API, можуть мати різні формати:

  • JSON (JavaScript Object Notation) — найпоширеніший формат для передачі структурованих даних через REST API через його простоту та легкість для аналізу як клієнтами, так і серверами.
  • XML (Extensible Markup Language) — використовується для передачі структурованих даних, але поступово втрачає популярність через складність у порівнянні з JSON. Однак все ще застосовується в деяких інтеграціях із системами або стандартами, які вимагають XML.
  • Plain Text (текст) — може використовуватися для передачі простих текстових даних або повідомлень. Часто застосовується для службових повідомлень або відповідей, які не вимагають складної структури даних.
  • HTML — використовується для передачі вебсторінок або фрагментів HTML-коду, зазвичай у випадках, коли REST API генерує контент для рендерингу у браузері.
  • Binary Data (бінарні дані)— REST API може передавати файли або інші бінарні дані, наприклад:
    • Зображення: image/jpeg, image/png, image/gif.
    • Документи: application/pdf, application/msword, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet (Excel).
    • Аудіо/відео: audio/mpeg, video/mp4.
  • CSV (Comma-Separated Values) — формат для передачі табличних даних, який використовується для експорту/імпорту даних у текстовому форматі, де поля розділені комами.
  • YAML (YAML Ain’t Markup Language) — менш поширений, але використовується у випадках, коли потрібно передавати дані в структурованому та зручному для людини форматі, подібному до JSON.
  • Form Data (форматовані дані форми) — дані, що передаються через форми (зазвичай використовуються в POST або PUT-запитах):
    • application/x-www-form-urlencoded — стандартний формат для передавання полів форми.
    • multipart/form-data — використовується для передавання даних із форм, включно з файлами.

Content-Type

Формат даних завжди вказується у заголовку Content-Type для правильного розуміння клієнтом або сервером структури переданих даних. Наприклад:

  • Content-Type: application/json
  • Content-Type: application/xml
  • Content-Type: text/html
  • Content-Type: multipart/form-data

Статус коди

Коди відповіді HTTP повідомляють про результат виконання запиту.

1xx Інформація:

  • 100 Continue — клієнт може продовжувати відправку запиту, оскільки сервер отримав початкову частину без помилок.
  • 101 Switching Protocols — сервер погодився на перехід до іншого протоколу, зазначеного клієнтом у запиті.
  • 102 Processing — сервер обробляє запит, але поки не може надати відповідь.
  • 103 Early Hints — сервер повертає ранні заголовки для оптимізації (наприклад, для передзавантаження ресурсів).

2xx Успіх:

  • 200 OK — запит успішно виконаний, і сервер повернув очікувані дані.
  • 201 Created — запит виконаний, і в результаті був створений новий ресурс.
  • 202 Accepted — запит прийнятий, але ще не оброблений (обробка виконується асинхронно).
  • 203 Non-Authoritative Information — запит виконаний, але інформація, що повертається, отримана від стороннього джерела.
  • 204 No Content — запит виконаний успішно, але у відповіді немає вмісту.
  • 205 Reset Content — запит виконаний успішно, але клієнту слід скинути стан відображення.
  • 206 Partial Content — сервер повертає лише частину ресурсу у відповідь на запит із заголовком Range.
  • 207 Multi-Status — сервер повертає кілька статусів для різних ресурсів.
  • 208 Already Reported — елемент уже був перелічений у попередній відповіді.
  • 226 IM Used — сервер успішно виконав запит і використовував варіант відповіді для цього запиту.

Перенаправлення (3xx):

  • 300 Multiple Choices — запитаний ресурс має кілька можливих варіантів, з яких клієнт може обирати.
  • 301 Moved Permanently — запитаний ресурс був переміщений на нову постійну URL-адресу.
  • 302 Found — запитаний ресурс тимчасово переміщений на іншу URL-адресу.
  • 303 See Other — клієнт повинен використовувати інше URL для отримання ресурсу.
  • 304 Not Modified — запитаний ресурс не змінився з часу останнього доступу.
  • 307 Temporary Redirect — запитаний ресурс тимчасово доступний за іншою URL-адресою, але метод запиту не змінюється.
  • 308 Permanent Redirect — запитаний ресурс переміщений на нову постійну URL-адресу, і метод запиту не змінюється.

Помилки клієнта (4xx):

  • 400 Bad Request — сервер не може обробити запит через помилку на стороні клієнта (некоректний синтаксис).
  • 401 Unauthorized — для доступу до ресурсу потрібна аутентифікація.
  • 402 Payment Required — зарезервований для майбутнього використання (наприклад, для платних послуг).
  • 403 Forbidden — сервер відмовляє у виконанні запиту через відсутність прав доступу.
  • 404 Not Found — сервер не може знайти запитаний ресурс.
  • 405 Method Not Allowed — метод запиту не дозволений для цього ресурсу.
  • 406 Not Acceptable — сервер не може повернути дані у форматі, прийнятному для клієнта.
  • 407 Proxy Authentication Required — клієнт повинен пройти аутентифікацію через проксі-сервер.
  • 408 Request Timeout — сервер чекав на запит клієнта занадто довго і припинив очікування.
  • 409 Conflict — конфлікт в обробці запиту, наприклад, при одночасній зміні ресурсу.
  • 410 Gone — ресурс більше недоступний і був видалений постійно.
  • 411 Length Required — сервер очікує заголовок Content-Length у запиті, але його немає.
  • 412 Precondition Failed — одна з передумов запиту не виконана (використовується із заголовками If-None-Match, If-Modified-Since тощо).
  • 413 Content Too Large — тіло запиту занадто велике для обробки сервером.
  • 414 URI Too Long — URI запиту занадто довгий для обробки сервером.
  • 415 Unsupported Media Type — сервер не підтримує тип даних, переданих у запиті.
  • 416 Range Not Satisfiable — запитаний діапазон не може бути задоволений, наприклад, якщо ресурс менший за запитаний діапазон байтів.
  • 417 Expectation Failed — сервер не може задовольнити заголовок Expect, надісланий клієнтом.
  • 418 I’m a teapot — жартівливий статус-код з RFC 2324 («Я чайник», використовується для гумористичних відповідей).
  • 421 Misdirected Request — запит був надісланий на неправильний сервер.
  • 422 Unprocessable Content — сервер не може обробити запит через проблеми з його вмістом (наприклад, некоректний формат).
  • 423 Locked — доступ до ресурсу заблокований.
  • 424 Failed Dependency — запит не може бути виконаний через невдачу іншого запиту.
  • 425 Too Early — сервер відмовляє в обробці запиту, оскільки він був надісланий занадто рано.
  • 426 Upgrade Required — клієнт повинен перейти на іншу версію протоколу для виконання запиту.
  • 428 Precondition Required — сервер вимагає, щоб запит мав передумови для виконання.
  • 429 Too Many Requests — клієнт надіслав занадто багато запитів за короткий час (обмеження швидкості).
  • 431 Request Header Fields Too Large — заголовки запиту занадто великі для обробки сервером.
  • 451 Unavailable For Legal Reasons — доступ до ресурсу заблоковано через юридичні причини.

Помилки сервера (5xx)

  • 500 Internal Server Error — загальна помилка сервера, яка не може бути деталізована.
  • 501 Not Implemented — сервер не підтримує метод або функцію, необхідну для обробки запиту.
  • 502 Bad Gateway — сервер отримав неправильну відповідь від іншого сервера.
  • 503 Service Unavailable — сервер тимчасово недоступний через перевантаження або технічне обслуговування.
  • 504 Gateway Timeout — сервер не отримав відповідь від іншого сервера вчасно.
  • 505 HTTP Version Not Supported — сервер не підтримує версію HTTP, яку використовує клієнт.
  • 506 Variant Also Negotiates — сервер не може завершити запит через внутрішній конфлікт у вмісті.
  • 507 Insufficient Storage — сервер не може зберігати необхідні дані для виконання запиту.
  • 508 Loop Detected — сервер виявив нескінченний цикл у запиті.
  • 510 Not Extended — сервер вимагає додаткових розширень для виконання запиту.
  • 511 Network Authentication Required — клієнт повинен пройти автентифікацію для доступу до мережі.

Ці коди дозволяють клієнту розуміти, чи був запит успішним, і, якщо ні, то яка саме проблема сталася.

Ідемпотентність

Ідемпотентність — це властивість операцій, яка означає, що багаторазове виконання однієї і тієї ж операції призведе до того самого результату, що і перше її виконання. Незалежно від того, скільки разів операція буде викликана, результат залишатиметься незмінним.

У контексті HTTP ідемпотентність важлива для забезпечення надійності запитів. Наприклад, якщо під час виконання операції мережа зазнала тимчасової проблеми, клієнт може безпечно повторити запит, не ризикуючи створити додаткові або небажані зміни на сервері.

Які HTTP-методи є ідемпотентними та чому

  1. GET — цей метод лише отримує дані із сервера, не змінюючи їх. Незалежно від кількості запитів, відповідь завжди буде тією самою (за умови, що дані на сервері не змінилися).
  2. PUT — метод призначений для створення або оновлення ресурсу на сервері. Якщо той самий ресурс відправляється кілька разів, він лише оновлюється або перезаписується, що не змінює результату операції.
  3. DELETE — видаляє ресурс. Незалежно від кількості викликів цього методу, результат завжди один і той самий — ресурс буде видалений. Повторні запити не призведуть до нових змін.
  4. HEAD — аналогічний до GET, але без повернення тіла відповіді. Цей метод також не змінює стан ресурсів на сервері.
  5. OPTIONS — використовується для запиту про доступні методи на сервері, тому не змінює дані й також є ідемпотентним.

Отже, основною характеристикою ідемпотентних методів є те, що їхнє багаторазове виконання не впливає на стан сервера після першого запиту, що робить їх безпечними для повторного використання у випадку помилок або збоїв.

Версіонування

Версіонування у REST API є важливим аспектом для підтримки зворотної сумісності при внесенні змін до API. Це дозволяє одночасно підтримувати кілька версій сервісу для різних клієнтів або застосунків, що можуть використовувати старіші версії.

Існують кілька способів реалізації версіонування API:

1. Версія у URL

Найпоширеніший спосіб — включати версію API у шлях URL. Це простий та інтуїтивно зрозумілий підхід.

Приклад:

GET /v1/users
GET /v2/users
  • У цьому прикладі /v1 і /v2 вказують на різні версії API. Це дозволяє змінювати структуру ресурсів або поведінку методів у нових версіях без порушення роботи старих клієнтів.

2. Версія у заголовках

Ще один підхід — передача версії через HTTP-заголовки. Це дозволяє зберігати чисті URL і перемикати версію API за допомогою спеціальних заголовків.

Приклад:

GET /users
Accept: application/vnd.myapi.v1+json
  • У цьому прикладі заголовок Accept містить версію API, яку очікує клієнт.

3. Версія у параметрах запиту

Також можна використовувати параметри запиту для передачі версії API. Це дозволяє передавати версію разом з іншими параметрами.

Приклад:

GET /users?version=1

Коли і як використовувати версіонування

Версіонування потрібне, коли:

  • Ви плануєте вносити зміни, які порушать зворотну сумісність.
  • Необхідно підтримувати кількох клієнтів, які використовують різні версії API.

Краще за все починати із версії з самого початку розробки API, навіть якщо ви не плануєте змін найближчим часом. Це дозволить вам уникнути проблем у майбутньому.

Принципи успішного версіонування

  • Зміни, які не впливають на клієнтів, не вимагають нової версії. Наприклад, додавання нових полів у відповіді.
  • Створюйте нову версію лише для критичних змін у логіці або структурі.
  • Старі версії слід підтримувати, але за можливості заохочувати клієнтів до міграції на новіші.

HATEOAS

HATEOAS (Hypermedia as the Engine of Application State) — це один із ключових принципів REST, що означає використання гіпермедіа для управління станом застосунку. Гіпермедіа тут означає використання гіперпосилань у відповідях API для надання клієнту можливості переходити між різними станами або ресурсами системи.

HATEOAS дозволяє клієнту взаємодіяти з сервером без попереднього знання про структуру ресурсів. Сервер надає всі необхідні посилання у відповідях на запити клієнта, що дозволяє клієнту «вивчати» API динамічно. Це підвищує гнучкість API та зменшує залежність клієнта від документованої структури URL.

Приклад. Клієнт запитує інформацію про користувача:

GET /users/123

Сервер відповідає, надаючи інформацію про користувача, а також гіперпосилання на інші пов’язані дії:

{
   "id": 123,
   "name": "John Doe",
   "links": [
    {
        "rel": "self",
        "href": "/users/123"
    },
    {
       "rel": "orders",
       "href": "/users/123/orders"
    },
    {
        "rel": "friends",
        "href": "/users/123/friends"
    }
    ]
}

У цьому прикладі сервер надає клієнту посилання на пов’язані ресурси, такі як замовлення користувача чи список друзів. Клієнт може використовувати ці посилання для подальших запитів, не знаючи наперед структури URL-адрес.

Модель зрілості Річардсона (Richardson Maturity Model)

Модель зрілості Річардсона описує етапи розвитку REST API за рівнями відповідності REST-принципам. Вона складається з чотирьох рівнів:

  1. Рівень 0 — POX (Plain Old XML) або RPC API: API використовує HTTP як транспортний протокол, але не використовує його можливості. Всі запити надсилаються на одну кінцеву точку, а методи роботи з даними обираються через параметри запиту. (POST-запит на одну url з різними request body.)
  2. Рівень 1 — Ресурси: API визначає різні кінцеві точки для різних ресурсів, таких як /users, /orders, тощо. Кожен ресурс має свою URL-адресу, але HTTP-методи використовуються ще не повною мірою. (POST-запити на різні url з різними request body.)
  3. Рівень 2 — HTTP-методи: API використовує стандартні HTTP-методи (GET, POST, PUT, DELETE) для взаємодії з ресурсами. Це дозволяє покращити масштабованість і зрозумілість API. (Будь-які HTTP-методи на різні url з різними request body.)
  4. Рівень 3 — HATEOAS: API не лише використовує ресурси та HTTP-методи, але й надає гіпермедійні посилання у відповідях, що дозволяють клієнту динамічно досліджувати API. Це найвищий рівень зрілості REST API.

Модель зрілості Річардсона допомагає оцінити, наскільки ваше API відповідає принципам REST та де воно може бути покращене для досягнення більшої гнучкості та масштабованості.

Як працювати з гіпермедіа

Щоб успішно інтегрувати HATEOAS у свій REST API, вам необхідно:

  1. Надавати корисні посилання. Для кожного ресурсу сервер повинен включати посилання на пов’язані ресурси або доступні дії. Наприклад, для користувача можна надати посилання на його замовлення, профіль, друзів тощо.
  2. Використовувати стандартні типи відношень. Посилання повинні містити атрибути rel (relationship), які визначають тип зв’язку між ресурсами. Наприклад, rel: self для посилання на поточний ресурс, або rel: orders для посилання на пов’язані замовлення.
  3. Документувати гіпермедіа. Попри те, що клієнт може динамічно досліджувати API через посилання, важливо надавати документацію для того, щоб розробники розуміли структуру і логіку взаємодії з вашим API.

Rate Limiting (Обмеження кількості запитів)

Rate Limiting — техніка обмеження кількості запитів, які клієнт може надіслати до сервера за певний проміжок часу. Це необхідний механізм для запобігання перевантаженню серверів і захисту від зловмисних дій, таких як DDoS-атаки або несанкціоноване використання API.

Rate Limiting працює за допомогою встановлення меж для кількості запитів, які клієнт може зробити протягом певного періоду часу. Коли клієнт перевищує ці межі, сервер може відповідати спеціальним кодом помилки (зазвичай 429 Too Many Requests), інформуючи про необхідність зменшити кількість запитів.

Приклад. Якщо сервер встановлює ліміт у 100 запитів на годину, після 100-го запиту клієнт отримає відповідь:

HTTP/1.1 429 Too Many Requests
Retry-After: 3600

Заголовок Retry-After повідомляє клієнту, через скільки секунд можна повторити запит.

Чому це важливо

  1. Захист від перевантаження: обмеження швидкості запитів допомагає запобігти перевантаженню серверів, що може спричинити погіршення продуктивності або збої в системі.
  2. Захист від зловмисних дій: rate limiting захищає від ботів або хакерів, які можуть намагатися несанкціоновано використовувати ваш API через часті запити.
  3. Ефективне використання ресурсів: це дозволяє ефективно керувати доступом до ресурсів і забезпечує справедливий розподіл пропускної здатності між клієнтами.

Як реалізувати Rate Limiting

  1. Token Bucket або Leaky Bucket. Це популярні алгоритми для обмеження кількості запитів.
      • Алгоритм Token Bucket — кожен клієнт має певний бакет з токенами, кожен токен дозволяє зробити один запит. Токени поступово додаються з певною швидкістю, і коли бакет порожній, клієнт має почекати перед новим запитом.
      • Алгоритм Leaky Bucket — подібний до Token Bucket, але всі запити обробляються з постійною швидкістю, навіть якщо клієнт намагається зробити кілька запитів одночасно. Це допомагає рівномірно розподіляти навантаження.
    1. Заголовки для інформації про ліміти. API може використовувати заголовки X-RateLimit-Limit (максимальна кількість запитів), X-RateLimit-Remaining (залишок запитів у межах ліміту) і X-RateLimit-Reset (час, коли ліміт буде скинутий).
    2. Поведінка при перевищенні ліміту. Сервер повинен повернути відповідь з кодом 429 Too Many Requests і додати заголовок Retry-After, щоб вказати, коли клієнт може повторити запит.

    CORS (Cross-Origin Resource Sharing)

    CORS — це механізм, який дозволяє веб-браузерам контролювати доступ до ресурсів з одного домену на іншому. Це критично важливий аспект безпеки REST API, оскільки він запобігає несанкціонованим доступам до API з інших доменів.

    Коли клієнт намагається звернутися до ресурсу з іншого домену, сервер має вказати в заголовку відповіді, чи дозволяє він цей доступ. Це відбувається через заголовки:

    • Access-Control-Allow-Origin. Вказує, з яких доменів дозволено доступ до ресурсу.
    • Access-Control-Allow-Methods. Вказує, які HTTP-методи дозволено для крос-доменного доступу.
    • Access-Control-Allow-Headers. Вказує, які заголовки можуть бути надіслані під час крос-доменного запиту.
    Приклад:
    Access-Control-Allow-Origin: https://example.com
    Access-Control-Allow-Methods: GET, POST, PUT

    Preflight-запити — коли браузер виконує запит із методом, відмінним від GET або POST, або з нестандартними заголовками, він спершу відправляє preflight-запит з методом OPTIONS, щоб дізнатися, чи дозволено виконання основного запиту. Це критично для безпеки, оскільки дозволяє серверам чітко контролювати, які запити можна виконувати.

    Пагінація та фільтрація

    Пагінація та фільтрація є необхідними для оптимізації роботи з великими наборами даних у REST API.

    Пагінація дозволяє поділити великі набори даних на сторінки, щоб уникнути передачі занадто великої кількості інформації за один раз. Зазвичай використовується для списків користувачів, замовлень або інших об’єктів.

    Приклад:

    GET /users?page=2&size=50

    У цьому прикладі клієнт запитує другу сторінку з 50 користувачами на сторінці.

    Фільтрація допомагає клієнтам отримати тільки ті дані, які їм необхідні, замість всього набору даних. Це може бути здійснено через параметри запиту.

    Приклад:

    GET /users?age=30&status=active

    Клієнт отримує список користувачів віком 30 років зі статусом «active».

    Додаткові заголовки для пагінації:
    • X-Total-Count. Вказує загальну кількість доступних ресурсів.
    • Link. Містить посилання на наступну та попередню сторінки.

    Безпека у REST API

    HTTPS (SSL/TLS)

    HTTPS (Hypertext Transfer Protocol Secure) — це безпечний протокол передачі даних через інтернет, який забезпечує шифрування даних між клієнтом і сервером за допомогою технологій SSL (Secure Sockets Layer) або TLS (Transport Layer Security). Він є критичним елементом для захисту REST API та веб-застосунків від атак і перехоплення даних під час передачі.

    Як працює HTTPS

    1. Шифрування
      • HTTPS використовує SSL або TLS для шифрування всіх даних, які передаються між клієнтом і сервером. Навіть якщо зловмисник перехопить трафік, він не зможе розшифрувати дані.
      • Під час встановлення з’єднання клієнт і сервер обмінюються сертифікатами для перевірки автентичності та встановлення шифрованого каналу.
    2. Аутентифікація
      • HTTPS забезпечує аутентифікацію сервера, що дозволяє клієнту впевнитись у тому, що він спілкується саме з тим сервером, до якого звертався, і не є жертвою атак типу «людина посередині» (Man-in-the-Middle).
    3. Цілісність даних
      • SSL/TLS гарантує, що дані, передані між клієнтом і сервером, не можуть бути змінені або пошкоджені під час передачі без виявлення.

    Основні компоненти HTTPS

    1. SSL/TLS сертифікат
      • Для встановлення HTTPS-з’єднання сервер повинен мати SSL/TLS сертифікат, виданий довіреним центром сертифікації (CA).
      • Сертифікат містить публічний ключ сервера та інші дані, які підтверджують його автентичність.
    2. Рукостискання (Handshake)
      • Під час першого з’єднання між клієнтом і сервером відбувається процес «рукостискання», де клієнт перевіряє сертифікат сервера, а сервер і клієнт узгоджують параметри шифрування для сесії.
      • Після цього встановлюється безпечне шифроване з’єднання.
    3. Шифрування даних
      • Після встановлення з’єднання всі дані передаються у зашифрованому вигляді. Навіть якщо зловмисник зможе перехопити трафік, він не зможе розшифрувати дані без приватного ключа сервера.

    Чому HTTPS важливий для REST API

    1. Захист конфіденційних даних
      • REST API часто передає конфіденційні дані, такі як токени автентифікації, паролі, платіжну інформацію тощо. HTTPS забезпечує, що ці дані залишаються захищеними під час передачі.
    2. Запобігання атакам типу «людина посередині» (Man-in-the-Middle)
      • HTTPS захищає від атак, коли зловмисник намагається перехопити або змінити трафік між клієнтом і сервером. Без HTTPS зловмисник міг би отримати доступ до конфіденційної інформації або змінювати запити і відповіді.
    3. Безпечний доступ до API
      • Багато сторонніх сервісів, таких як платежі або авторизація (OAuth2, JWT), вимагають використання HTTPS для роботи з REST API, щоб забезпечити безпечну передачу даних.
    4. Захист від підроблених сайтів
      • HTTPS гарантує, що користувач або клієнт звертається до справжнього сервера, а не до підробленого ресурсу, який може бути створений зловмисниками.

    Приклад налаштування HTTPS для Java/Spring

    1. Отримання SSL-сертифікату
      • Ви можете отримати сертифікат від довіреного центру сертифікації (CA) або використовувати безкоштовні сертифікати, наприклад від Let’s Encrypt.
    2. Налаштування HTTPS у Spring Boot
      • Після отримання сертифіката його потрібно налаштувати в Spring Boot.

    Додайте налаштування до файлу application.properties або application.yml:

    server.port=8443
    server.ssl.key-store=classpath:keystore.p12
    server.ssl.key-store-password=yourpassword
    server.ssl.key-store-type=PKCS12
    server.ssl.key-alias=youralias
    • Використання Java Keystore (JKS)

    Створіть keystore для зберігання сертифікатів за допомогою інструменту keytool, який входить у JDK:
    keytool -genkeypair -alias youralias -keyalg RSA -keystore keystore.p12 -storetype PKCS12 -validity 365 -keysize 2048

    • Переведення Spring Boot додатка на HTTPS

    Після налаштування сертифіката всі запити до вашого REST API будуть автоматично зашифровані за допомогою HTTPS.

    Висновок

    HTTPS (SSL/TLS) є обов’язковим для захисту REST API від перехоплення даних і атак. Він забезпечує:

    • Шифрування переданих даних.
    • Автентифікацію сервера.
    • Цілісність даних під час передачі.

    Це робить HTTPS необхідним компонентом для будь-якого API, який працює з конфіденційною інформацією або передає критично важливі дані.

    XSS (Cross-Site Scripting)

    Cross-Site Scripting (XSS) — це тип вразливості безпеки веб-додатків, який дозволяє зловмисникам вставляти шкідливі скрипти на вебсторінки, що можуть виконуватися на стороні клієнта (у браузері). Зазвичай це відбувається, коли дані, введені користувачем або отримані з іншого джерела, не фільтруються належним чином перед відображенням у браузері.

    Основні типи XSS

    1. Stored XSS (Збережений XSS)
      • Шкідливий скрипт зберігається на сервері в базі даних або іншому сховищі. Коли інший користувач відвідує сторінку, скрипт завантажується та виконується у його браузері.
      • Приклад. Зловмисник вводить шкідливий скрипт у форму коментарів на сайті. Коли інші користувачі переглядають сторінку з коментарями, їхні браузери виконують цей скрипт.
    2. Reflected XSS (Відображений XSS)
      • Шкідливий скрипт передається у URL або параметрах запиту і негайно відображається в відповіді сервера без збереження на сервері.
      • Приклад. Зловмисник створює посилання, яке містить шкідливий скрипт. Коли користувач переходить за цим посиланням, скрипт виконується у браузері жертви.
    3. DOM-Based XSS
      • Вразливість виникає через маніпуляції з Document Object Model (DOM) на клієнтській стороні без взаємодії з сервером.
      • Приклад. Сайт виконує небезпечні зміни в DOM на основі неконтрольованого вводу даних користувача.

    Як XSS впливає на REST API

    REST API, хоч і не безпосередньо пов’язані з відображенням контенту на вебсторінці, все ж можуть бути вразливі до XSS-атак. Особливо коли дані, отримані від API, вставляються у вебсторінку без належної фільтрації. Це може статися, наприклад, при розробці SPA (Single Page Applications) або у випадках, коли API повертає HTML або JavaScript.

    Наслідки XSS

    • Викрадення сесій— зловмисники можуть викрасти сесійні кукі або токени автентифікації користувача.
    • Виконання шкідливого коду — шкідливий код може виконуватись на боці клієнта, відкриваючи можливості для подальших атак.
    • Фішинг — зловмисники можуть використовувати XSS для створення підроблених сторінок або форм для отримання конфіденційної інформації.

    Захист від XSS

    1. Фільтрація вводу
      • Валідуйте і фільтруйте всі вхідні дані, перш ніж зберігати їх або використовувати для відображення.
      • Використовуйте списки дозволених символів (whitelisting), а не списки заборонених (blacklisting).
    2. Екранування виводу (Output Escaping)
      • Будь-який динамічний контент, що відображається на сторінці, повинен бути екранований. Це означає, що небезпечні символи, такі як <, >, «, ’, повинні бути замінені на їхні HTML-коди (<, >, », ').
      • Екрануйте дані залежно від контексту (в HTML, JavaScript, атрибутах тощо).
    3. Content Security Policy (CSP)
      • Впровадження політики безпеки контенту допоможе обмежити виконання скриптів, які не були явно дозволені. Це може запобігти виконанню вбудованих або сторонніх скриптів. Приклад заголовку CSP:
        Content-Security-Policy: default-src ’self’; script-src ’self’;
    4. HTTP-only кукі
      • Встановлюйте кукі з прапором HTTP-only, щоб вони не були доступні для JavaScript у браузері. Це знижує ризик їх викрадення через XSS.
    5. Фреймворки з вбудованим захистом
      • Використовуйте фреймворки з вбудованими механізмами захисту від XSS (React, Angular) — ці фреймворки автоматично екранують динамічний контент, що робить додатки більш безпечними.
    Приклад захисту:

    Якщо ваш REST API повертає дані, які будуть відображені у веб-інтерфейсі, екрануйте та валідуйте їх перед відображенням.

    <p>User name: <script>alert('XSS')</script></p>

    Після екранування:

    <p>User name: &lt;script&gt;alert('XSS')&lt;/script&gt;</p>

    CSRF (Cross-Site Request Forgery)

    Cross-Site Request Forgery (CSRF) — це тип атак на веб-застосунки, в якому зловмисник змушує користувача виконати небажану дію на іншому сайті, на якому користувач вже автентифікований. Атаки CSRF відбуваються, коли користувач завантажує шкідливий сайт, який таємно відправляє запит до іншого сайту, використовуючи сесію або кукі користувача для автентифікації.

    Як працює CSRF

    1. Зловмисник створює шкідливий сайт або посилання.
    2. Користувач заходить на цей шкідливий сайт або натискає на посилання, будучи автентифікованим на іншому сайті (зазвичай через збережені сесійні кукі).
    3. Запит відправляється до іншого сайту (де користувач автентифікований), використовуючи його сесію без його відома.
    4. Сайт виконує дію, оскільки запит виглядає законним з боку автентифікованого користувача.

    Приклад атаки CSRF

    Припустимо, користувач вже увійшов на банківський сайт, і у нього збережена сесія через кукі. Зловмисник надсилає користувачу посилання на шкідливий сайт, який таємно виконує POST-запит до банку на переведення коштів:

    <form action="https://bank.com/transfer" method="POST">
        <input type="hidden" name="toAccount" value="hacker_account">
        <input type="hidden" name="amount" value="10000">
        <input type="submit">
    </form>

    Як тільки користувач відвідує шкідливий сайт або посилання викликається через JavaScript, відправляється запит, і банк виконує дію, оскільки користувач уже автентифікований.

    Наслідки CSRF

    • Небажані дії — користувач виконує дію, яку він не мав наміру виконати (наприклад, перерахування грошей, зміна налаштувань, видалення даних тощо).
    • Безпека даних — CSRF може призвести до компрометації конфіденційної інформації або даних користувачів.
    • Витрата ресурсів — сайти можуть отримувати небажані запити, що призводить до навантаження на сервери або втрати ресурсів.

    Захист від CSRF

    CSRF-токени:

    • Найбільш ефективним методом захисту від CSRF є використання унікальних CSRF-токенів. Кожен запит до сервера, що змінює стан (наприклад, POST, PUT, DELETE), повинен містити CSRF-токен, який перевіряється сервером.
    • Як це працює: Коли користувач завантажує форму або вебсторінку, сервер генерує CSRF-токен і додає його до форми або в заголовок. При відправленні запиту сервер перевіряє наявність та коректність токена.

    Приклад CSRF-токена в HTML:

    <form action="/submit" method="POST">
        <input type="hidden" name="csrf_token" value="RANDOM_TOKEN_VALUE">
        <input type="submit" value="Submit">
    </form>
    HTTP-заголовки (SameSite Cookie Attribute):
    • Встановлення атрибуту SameSite для кукі, щоб обмежити можливість використання кукі з іншими сайтами:
      • SameSite=Lax — дозволяє надсилати кукі тільки з першорядними запитами (GET-запитами, коли користувач натискає посилання).
      • SameSite=Strict — кукі не відправляються при переході з іншого домену, що забезпечує кращий захист від CSRF.

    Приклад кукі із атрибутом SameSite:
    Set-Cookie: sessionId=abc123; SameSite=Strict

    1. Використання методів HTTP, що безпечні від CSRF
      • CSRF атаки зазвичай працюють через методи GET або POST, але методи PUT, PATCH, DELETE рідко використовуються у випадках CSRF, оскільки форми зазвичай використовують метод POST. Втім, вони також повинні бути захищені.
    2. Перевірка Referer або Origin заголовків
      • Сервер може перевіряти заголовки Referer або Origin, щоб переконатися, що запити надходять з довіреного джерела (наприклад, із сайту вашого додатку). Це не ідеальний захист, але може бути використаний як додатковий рівень безпеки.

    Приклад:

    Referer: https://yourapp.com/
    Origin: https://yourapp.com/
    1. Double Submit Cookie
      • В цьому методі сервер генерує токен CSRF і зберігає його у вигляді кукі, а також відправляє його на клієнтську сторону для додавання в запити (в заголовок або тіло запиту). Сервер потім порівнює токен з кукі з тим, що надійшов у запиті.

    Приклад захисту з CSRF-токенами

    Якщо ви використовуєте форму для відправлення запиту, додайте унікальний CSRF-токен до кожної форми:

    <form action="/transfer" method="POST">
        <input type="hidden" name="csrf_token" value="generated_csrf_token">
        <input type="text" name="toAccount">
        <input type="submit" value="Transfer">
    </form>

    Висновок

    CSRF є однією з основних загроз для безпеки REST API і веб-додатків, яка може бути вирішена за допомогою CSRF-токенів, атрибуту SameSite для кукі, і додаткових заходів, таких як перевірка заголовків або використання методів HTTP з кращим захистом. Правильне впровадження цих технік допоможе захистити ваші API та користувачів від несанкціонованих дій.

    Асинхронність у REST API

    REST API за своєю природою підтримує синхронну модель комунікації, де клієнт відправляє запит і отримує відповідь у межах одного з’єднання. Проте існують різні підходи, які дозволяють реалізувати асинхронну комунікацію в REST API, щоб обробляти довготривалі операції або отримувати дані без постійного опитування сервера.

    1. Polling (Опитування)

    Polling — це метод, при якому клієнт періодично надсилає запити на сервер, щоб дізнатися про статус операції або отримати нові дані. Це може бути корисно, коли обробка запиту займає певний час, і клієнт періодично опитує сервер на предмет змін.

    • Приклад. Клієнт може надіслати запит на створення ресурсу і отримати відповідь з кодом 202 Accepted. Потім він періодично надсилає запити на статус ресурсу через певні інтервали часу.
    • Недолік. Постійне опитування збільшує навантаження на сервер і може бути неефективним.

    2. Long Polling (Довге опитування)

    Long Polling працює подібно до звичайного опитування, але сервер тримає з’єднання відкритим, поки не з’являться нові дані або зміни. Це дозволяє знизити частоту запитів, оскільки сервер відповідає тільки тоді, коли є нові дані.

    • Приклад. Клієнт робить запит до сервера, і сервер затримує відповідь до моменту появи необхідних даних (наприклад, завершення операції).

    3. Webhooks

    Webhooks дозволяють серверу надсилати дані безпосередньо клієнту, коли подія відбувається. Це ефективний спосіб для асинхронної комунікації між сервісами або для оновлення статусу клієнта без необхідності постійного опитування.

    • Приклад. Клієнт реєструє URL для webhook, і коли сервер завершує обробку завдання, він надсилає HTTP POST-запит на цей URL з результатами. Це типово використовується для сервер-до-сервер інтеграцій.
    • Недоліки. Webhooks можуть бути ненадійними, якщо клієнтський сервер недоступний у момент надсилання запиту​.

    Висновок

    Хоча REST API зазвичай асоціюється з синхронними запитами, існують кілька перевірених підходів для впровадження асинхронної комунікації, таких як polling, long polling, webhooks, та WebSockets. Вибір методу залежить від специфіки вашого проєкту і частоти оновлень, які необхідні клієнту.

    👍ПодобаєтьсяСподобалось51
    До обраногоВ обраному50
    LinkedIn
    Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
    Ctrl + Enter
    Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
    Ctrl + Enter

    До речі, якщо пішла така п’янка, то про content negotiation не сказано

    Хлопцы, а к то делал все методы POST на проекте? Преимущество такого подхода очевидны, в теле запроса POST можно передавать большие объемы данных, что может быть удобно для сложных запросов, в том числе поисковых. Это дает большую универсальность, потому что так уже так уже были реализованы все методы API и сейчас разработчики продолжают поддерживать дизайн API в том же стиле.
    Если, да, то какие были последствия, и шё это был за проект, если не секрет конечно?

    Всі методи POST використовуються у SOAP та GraphQL. Не зовсім REST, але шо маємо.
    Наслідки:
    — GET по-ідеї є ідемпотентним* і тому може кешуватись проксями або клієнтськими бібліотеками;
    — POST так не кешується, тому треба городити якісь свої велосипеди, щоби кешувалось

    * це в ідеалі

    То шё приходит сразу на ум, отсутствие идемпотентности, повторное выполнение одного и того же POST-запроса может привести к разным результатам. И другое, это несоблюдения договоренности, т.к. принципы REST подразумевают использование различных HTTP-методов для разных CRUD-операций (GET для получения, PUT для обновления и т.д.). Вроде остальных сложностей нет, если я ошибаюсь, поправьте меня в комментах. HTTP-кэширование обычно применяется к GET-запросам, это не критично, т.к. для того что бы закешировать POST-запросы, необходимо установить соответствующие заголовки в ответе сервера. Например, можно использовать заголовки Cache-Control, Expires, ETag и Last-Modified. Эти заголовки помогут кешу понять, как долго хранить ответ и когда его следует обновить.

    Cache-Control: public, max-age=3600
    
    Или использовать специальные условия для POST-запросов, которые могут быть закешированы, если они содержат ясную информацию о свежести данных. Например, можно использовать заголовок
    Content-Location
    , чтобы указать на ресурс, который можно кешировать, или кешировать через прокси сервера, например Nginx

    Если техлид сказал делать пост то делай пост.

    За згадування філдінга лайк,

    стаття виходить далеко за межі REST, але мабуть так і треба 👌 не бу казати нічо про кешування і секуріті, але про рест власне можна

    Оригінально REST мав вирости в новий протокол і те що називають Web3.0, розширення HTTP з кастомними методами бо стандартний HTTP погано натягується на ідеальний світ REST. Плюс event-driven підхід не існував ще взагалі як поняття, все було ріквест-респонс. Полінг тут зовсім збоку.

    Але вийшло не революційно, а те що описано в статті, купа loosely-defined conventions, що потім обросли ще заходами безпеки. В хорошому сенсі GraphQL і полінг це реакція на недоліки REST-підходу, але насправді це не недоліки REST як такого а недоліки недосконалостей HTTP як основного протоколу RPC для web в парадигмі REST

    Ну це єсі пишно.

    Якщо не пишно, то на JSON+REST і потім twitter bootstrap було нереально зручно кліпать всякі круди й адмінки, REST як такий всім був до лампочки, всі кліпали той рест як хотіли й по різному, бо всі ненавиділи SOAP, WSDL, XML і думали що JSON, пара HTTP-методів і структурний конвеншен на рівні API — все що треба для SOA і все майбутнє. Всі текли на SOA, але не хотіли складностей XML. За десять років погризли кактус і тепер у нас json зі схемами, openapi ітп. Винайшли велосипед короче, пройшовши по колу. Чи варто було хз. Як на мене XML так елегантніше за сучасний JSON, але більш жорстко типвзований.

    Була ще CORBA з проміжною мовою — точь в точь протобаф але без брокера. Наше новоє виявляється всєголіш красіво спіжженоє староє ;)

    SOAP, CORBA, REST, protobuf — все це різні танці навколо одної й тої ж теми SOA
    Викинувши на смітник XMLRPC, індустрія останні 20 років винаходить той самий велосипед і натягує його на JSON і хттп

    Ну в кінці кінців течка на SOA вилилось в сучасну течку на мікросервіси. Мікросервіси були ще за царя гороха, хто курив справжню JEE а не J2SE+Spring, той не дасть збрехати :) JAR формат на рівні маніфестів підтримує SOA. Єдина різниця що не через HTTP. І тут упс згадуємо protobuf і всякі бінарні «покращення» HTTP. Чергове коло. Оригінальний Web3.0 помер, тепер цим називають щось зовсім інше.

    Короч суть в чому — що хоч філдінгу й приписують термін, але його ідеалізоване бачення настільки виявилось від реальності відірваним, що крім назви REST у сучасному програмуванні він має до нього абсолютний нуль відношення. Бо все що він там собі науявляв виявилось нікому непотрібним пшиком а потрібним виявилось описане в статіті. Полінг, секуріті, бінарні покращення для по суті варіанта RPC.

    Я взагалі не люблю цей термін, він не значить рівно нічого конкретного крім поумнічать. Є два варіанти віддалених викликів — CRUD з мінімальним фунаціональним навантаженням та всі інші RPC виклики. REST красиво працює рівно поки CRUD вистачає, а коли треба щось в плані transfer money from joe to sabrina — REST розвалюється. Там де по суті треба вліпити один нещасний толковий RPC виклик треба городити якісь абстрактні ресурси для транзакції й натягувати той ресурс на GET, PUT, DELETE ітд. Нафіга ото лиш рвати волосся на дурній голові й городити город я хз )

    Ну такий от екскурс, і стаття класна, просто вона не про REST філдфнга ;) Можна це ще по іншому розвернути — graphql чи eventdriven підхід поширюються як пожежа, вирішуючи проблеми, в той час як академічний ідеал hateoas філдінга вже більше 20 років не може переконати цих бекендщиків та формокліпатєлєй що він взагалі потрібен.

    Ну в кінці кінців течка на SOA вилилось в сучасну течку на мікросервіси. Мікросервіси були ще за царя гороха, хто курив справжню JEE а не J2SE+Spring, той не дасть збрехати :) JAR формат на рівні маніфестів підтримує SOA. Єдина різниця що не через HTTP. І тут упс згадуємо protobuf і всякі бінарні «покращення» HTTP. Чергове коло.

    В цілому так, але зайшли на нове коло з новими / зміненими:
    — вимогами (по пам’яті та CPU перестало влізати на одну машину через кількість фіч та юзерів)
    — тулзами (трейсінг ремоут викликів, кращі безкоштовні БД, деплоймент)
    — підходами розробки (своя БД кожному сервісу, не шаримо код між сервісами і тп).

    Щось нове взагалі як то тулзи, а в цілому це нова більш успішна комбінація. Додатків для великої кількості юзерів доречі теж стало набагато більше за рахунок пересічного юзера (додатки для лікарні, пошти, банкінгу, транспорту і тп), тому й попит виріс на таку розробку.

    Та десь так, роздуті інфраструктури з роздутими вимогами і от чи варто воно ото :)

    це нова більш успішна комбінація

    Щось згадалося, гг, ето йещо как сказать

    www.tomshardware.com/...​during-crowdstrike-outage

    Виявляється можна у 2024 і на допотопній вінді політати без проблем

    Якщо дивитися на це не з кількісної перспективи (сотні сервісів), а з архітектурної (окремі бази для сервісів та нормальна ізоляція домену в сервісі), то може й бути варте навіть з точки зору наскільки гарно воно працює (хоча витрати на сервери будуть вищими). Наприклад одна база все не витягує. Чи різні вимоги до доступності та живучості різних сервісів.

    Причому ж може бути наприклад 10-20 сервісів, але все одно в залежності від того як організувати код та дані, то буде або SOA або мікросервіси.

    Раніше теж було щось середнє між SOA та мікросервісами (гібрід такий собі). Наприклад якщо відділити репортінг та ще щось в окремі бази та сервери, щоб воно не навантажувало операційну базу та сервери. Але те що залишилося, працює на одній базі. Тобто може й не моноліт, а SOA, але ще можуть бути залежності між сервісами через базу та shared бізнес чи доменний код.

    Дуже насичено, дякую за структурований виклад! Багато корисного для себе взяла

    Гарно зібрано в одному місці мабуть майже все, що відноситься до REST (хоча багато чого відноситься до суміжних речей, но хай буде за REST)! Така собі стаття-посібник, де можна швидно пробігтися і побачити, що, наприклад упустив з виду при реалізації і т.д.

    Дякую за статтю! Мені цікаво які б мали бути умови, щоб обрати версіонування через заголовки або query param, наприклад?

    P.S. У розділі «Захист від XSS» приклад захисту, «до» і «після» екранування однаковий.
    P.P.S. В

    Як працює CSRF

    п.1, пробіл викрали.

    наприклад, якійсь дебільні обмеження на клієнтах, що користуються цим АПІ по типу не можна змінювати URL

    XSS (Cross-Site Scripting)

    Cross-Site Scripting (XSS) — це тип вразливості безпеки веб-додатків, який дозволяє зловмисникам вставляти шкідливі скрипти на вебсторінки, що можуть виконуватися на стороні клієнта (у браузері).

    Який стосунок все це має до REST API?
    Після прочитання даного посту створюється враження, що автор вирішив в одному місці написати все, що він знав про Web, а для того, щоб отримати більше переглядів, вигадав клікбейтний заголовок «Повний огляд REST»

    Тут как раз все просто! Это даже я на 3 курсе знаю! XSS-атаки могут использовать или эмулировать AJAX-запросы к REST API для выполнения вредоносного кода. Если страница загружает данные через AJAX без проверки их безопасности, это может привести к выполнению вредоносных скриптов. Многие современные веб-приложения используют JavaScript для взаимодействия с REST API. Если приложение получает данные от API и отображает их на странице без надлежащей обработки, это создает возможность для XSS-атак. Например, если API возвращает комментарии пользователей, и эти комментарии не экранируются, злоумышленник может вставить JavaScript-код в комментарий. И главное, взаимодействие с клиентом: REST API часто используется для обмена данными между клиентом и сервером. Если API возвращает данные, которые не проходят должную валидацию или экранирование, это может привести к уязвимостям XSS. Например, если API возвращает данные, введенные пользователем, без должной обработки, злоумышленник может вставить вредоносный код.

    Говорилось не о том, просто это или не просто. Говорилось о том, что отношения к РЕСТу имеет посредственное (с чем я полностью согласен)

    Вы серьезно? XSS имеет прямое отношение к REST в контексте безопасности веб-приложений, хотя бы потому, что правильная обработка входных и выходных данных является критически важной для предотвращения XSS-атак.

    Правильно, XSS имеет прямое отношение в контекте безопасности веб-приложений, а не к RESTу как таковому. REST — это прежде всего архитектурный стиль.
    А то так можно сказать, что и оптоволокно имеет прямое отношение к REST, потому как по нему часто гоняется

    Величезна проблема багатьох технічних статей на DOU у тому, що люди, які їх пишуть, або погано розуміються на темі, або не можуть точно описати матеріал. Наприклад:

    Сам REST запит складається з таких частин:

    Метод HTTP.
    Посилання.

    REST/REST API — архітектурний принцип, який не пов’язаний з реалізацією. І там ніяк не описується, з чого має складатися запит. А те, що перераховує автор — це витяг зі специфікації HTTP.

    Величезна проблема багатьох технічних статей на DOU у тому, що люди, які їх пишуть, або погано розуміються на темі, або не можуть точно описати матеріал

    Ну ты в этом плане тоже не блистаешь. Лучше конечно чем тс этого топика, но тоже где-то рядом с ним.

    Ти ж був Олег Олег

    И sergiy sergiy я кстати был тоже)

    Просто у авторов отсутствует инженерное мышление. С моей точки зрения, лучше было бы написать так, хотя метод HTTP и URI являются важными компонентами REST-запроса, они не исчерпывают всей сложности и гибкости архитектуры REST. Полное понимание REST требует учета всех его принципов и ограничений, которые обеспечивают эффективное взаимодействие между клиентом и сервером. Например, архитектурные ограничения: REST основывается на нескольких архитектурных ограничениях, таких как:
    Единый интерфейс: Это означает, что все взаимодействия с ресурсами должны происходить через стандартный интерфейс. Каждый ресурс должен быть уникально идентифицируемым с помощью URI, а операции над ресурсами должны использовать стандартные методы HTTP (GET, POST, PUT, DELETE и т.д.) .
    Статусность: Каждое взаимодействие между клиентом и сервером должно быть независимым. Сервер не должен хранить состояние клиента между запросами. Это означает, что каждый запрос должен содержать всю необходимую информацию для его обработки, их там помоему еще три если не ошибаюсь.
    Утверждение, что REST-запрос состоит только из метода HTTP и ссылки, является упрощением и не отражает полной картины архитектуры REST. Хотя метод HTTP и URI (Uniform Resource Identifier) действительно играют ключевую роль в REST, сам принцип REST включает в себя гораздо больше аспектов, которые определяют, как должны взаимодействовать клиент и сервер.
    122-ая forever!

    Попустись трошки, у тебе статті теж не ідеальні

    А звідки взагалі взявся другий принцип про URL?
    Таке найменування було/є настільки розповсюдженим і небажаним водночас, що це вирішили винести в окремий принцип?

    Мабуть, регулярно хтось творить таке.
    Проблема «іменник чи дієслово?» взагалі одна з перших в іменуванні.

    Гарна стаття для тих хто вперше чує про rest, щоб зрозуміти що мають на увазі під цим. Та про сам rest хотілося б більше, а саме: про проектування, про зв’язки, про поширені патерни і проблеми. І менше про http, tls/ssl та секуріті. Все ж таки, то окремі топіки.

    Гарна стаття для тих хто вперше чує про rest, щоб зрозуміти що мають на увазі під цим.

    Якраз для новачка, ця стаття — повна хна, вона не пояснює РЕСТ, а фактично підміняє його на «API over HTTP» (+ певні практики веб-дев).
    Краще все ж починати з класики (якщо задача розуміння, а не нахапатись якихось слів):
    — martinfowler.com/...​hardsonMaturityModel.html — вступ, коротко про ідеї
    — ics.uci.edu/...​pubs/dissertation/top.htm — власне дисертація Філдінга, досить просто написана
    — restcookbook.com — це типові рішення, певен деякі з них продубльовані в статті
    — Огляд ХТТП кодів хоча б з вікі

    Ну і раз вже довелось писати комент, то і по статті:

    Хоча REST API зазвичай асоціюється з синхронними запитами, існують кілька перевірених підходів для впровадження асинхронної комунікації, таких як polling, long polling, webhooks, та WebSockets.

    Висновки мають бути підтверджені в основній частині статті. WebSockets не згадуються в тілі статті. То що вони роблять у висновках? Та і в РЕСТ архітектуру вони не дуже вписуються. Звісно є СТОМП, який не лише для них, але про нього в статті теж не згадується, та він теж не про РЕСТ, а про спосіб імітувати ХТТП.
    Класичне флоу для асинхронних процесів теж нормально не описано, просто згадані деякі з підходів, які на додачу не є філософськи РЕСтом.

    Напишіть, будь ласка, тоді хорошу статтю для новачків і не тільки, щоб обмежити к-ть таких коментарів і надати класну інформацію спільноті!)

    Филдинг уже написал целый диссер. Нах тебе ещё статья?

    Дуже корисно як шпаргалка. Додав у закладки

    Стаття заради статті, фактично ні про що, без жодної глибини. Піднято купу тем, які взагалі існують окремо і не залежать від того, REST це чи ні. Вони просто додані для збільшення кількості слів. Приклади примітивні, немає жодного порівняння з іншими стилями.

    Чого можна навчитися з цієї статті? Тільки того, що можна передавати лінки в респонсі? В «повному огляді REST...» про рест не більше 15% статті, де 10% з них просто про http.

    Чому тоді на співбесідах кандидати вперше чують про Richardson Maturity Model?

    Чому тоді на співбесідах кандидати вперше чують про Richardson Maturity Model?

    Чому ви задаєте це питання у відповіді на той коментар? Як дана стаття має це змінити, особливо враховуючи те що інформація про неї була не просто доступна до цієї статті, а іактивно форсилась у професійних колах (хоча б через ті самі співбесіди)?

    Навіть в публікації Фаулера більше інфи на цю тему ніж в цій статті. А там коротко і розраховано на досвідчених людей.

    Це відповідь на репліку, що стаття ні про що. Очевидно, що стаття для новачків.

    Статья — дезориентирующий бред. Из этого полотна текста из абсолютно рандомных тем у народа формируется вообще ложное понимание рест. Вообще не понимаю как такие синиор джава с покерфейсом, не сгорают от стыда, когда постят такие статьи. Это же читают коллеги, будущие коллеги это тоже прочтут. Ерам тоже зашквариться от этого.

    Бо це основа для rest, як нормальні форми для баз данних. Я реально сходу не розповім теорію про 3 (хоча б них, не 6) нормальні форми в базах, хоч з ними працюю дууже багато років, про якісь оптимізації, тюнинг, підводні камені при хайлоді можу сказати, а про нормальні форми ні, треба перечитати (звісно що структуру таблиць зроблю згідно нормалізації, та якщо відомі прогнозовані навантаження, то і де нормалізації де треба).

    hateaos взагалі на практиці для rest досить сумнівна штука.

    Щодо HATEOAS думаю представники фронтенду не погодяться, з цим зручно працювати.

    Чудова стаття, велике спасибі за роботу!
    Охопили великий спектр, кому треба глибше — можна зануритися, а так все зрозуміло і корисно.

    А як на вашу думку має виглядати restful ресурс скажімо для трансферу коштів або ендпойнт, який буде представляти дію між двома ресурсами?
    Просто POST /transfers
    Чи доречніше
    /transfers/{account-id-1}/{account-id-2}
    ?

    Краще не вказувати ці дані як path variables в url для більшої секʼюрності, безпечніше буде передавати через request body

    Тільки через секюрність? А якщо ми будемо мати alias-ids?

    Якщо alias-ids правильно впроваджені (без прив’язки до чутливих даних), їх використання в URL для RESTful API є хорошою практикою. Ви можете реалізувати як POST /transfers/{alias-id-1}/{alias-id-2}, так і POST /transfers із передачею alias-ids у тілі запиту, залежно від того, що більше відповідає вашій архітектурі. Але для максимальної безпеки краще залишати ідентифікатори в тілі запиту, особливо якщо мова йде про чутливі операції, як-от фінансові транзакції.
    Але я би все таки радив робити через request body, як мінімум щоб не роздувати url та збільшити секʼюрність.

    А яким чином написання/впровадження тим чи іншим чином впливатиме на архітектуру?
    На мій погляд роздувають зараз body, а не uri

    ех, цікаво, чи хоч раз в житті я побачу API яке реально імплементить декілька десятків HTTP кодів

    те що я бачу, це зазвичай апішки підтримують буквально штук 5 кодів. а-ля
    200 — все норм
    400 — ти дурак
    401 — ти хто?
    404 — шо? куди? нема такого
    500 — я дурак

    і що цікаво — зазвичай цього абсолютно достатньо для побудови інтеграції))

    P. S. хоча декілька моїх сервісів підтримують код 418 😌

    Я ще часто використовую/стикаюся з
    201 — все добре, ресурс створено
    204 — все окей, але ніц не знайдено
    405 — не той метод, дурнику
    409 — назріває конфлікт, треба шось міняти
    415 — що це за тип даних, мені таке не треба
    )))

    Але й інші можуть знадобитися/трапитися, просто набагато рідше)

    я полюбляю 422 — начебто структура ок (тобто на 400 — ти дурак), але валідацію не пройшло

    Какой код ответа на метод POST: 200 или 201?

    Ты сам хоть понял что спросил?
    ЗЫ. Такое чувство что ворвался и умничаешь, лишь бы поспорить или «блеснуть знаниями», пытаясь кого-то выставить менее компетентным

    декілька моїх сервісів підтримують код 418

    як би то спитати шоб ви не образилися...от завжди було цікаво...у чому прикол використовувати це в проді?...чи це такий завуальованій спосіб образити фронтів?

    це завуальований спосіб розважити себе якщо працюєш на апворк-шлюпці і на проекті ти і бекендщик, і фронт, і куа, і девопс, і хто завгодно)

    Як на мене, замовник платить гроші і очікує якості (він не повинен вміти розбиратися в тому, якісно ми пишемо чи не дуже, це наша відповідальність), як він повинен потім все це підтримувати? Додатково витрачати ресурси на те, що ми хотіли побавитися за його гроші?

    Сам люблю 418 :) Не для образи, зазвичай коли помилка пов’язана з бізнес логікою, і важко описати іншими кодами.
    Ну і такє специфічне легко потім в логах шукати, відразу видко і при дебагу

    и как клиент должен на него реагировать? Вот реально, что это даст ему для решения возникшей проблемы?

    что проблема — не типичная, раз использован такой код. что это где-то почти 500, но все же под контролем, ничего не сломалось, но ...

    а реагировать — ну так это от клиента зависит, может на все 4** и 5** у него один хендлер, так что теперь, и остальные коды не использовать :)

    как это, 4хх почти что 500 ? 4хх говорит о том, что идиот — клиент, а не сервер. Зачем клиенту говорить, что он делает что-то не так, если проблема не в нём?
    ЗЫ. Если у клиента на все 4хх и 5хх — то это какой-то треш.

    как это, 4хх почти что 500

    А так, ошибка где-то в core проявляется.

    говорит о том, что идиот — клиент, а не сервер.

    Да, потому что кроме формата данных, надо бы и бизнес-логику соблюдать :)

    Зачем клиенту говорить, что он делает что-то не так, если проблема не в нём?

    В нем.
    5** — это то что клиент не может исправить.
    а 4** — что может.

    Если у клиента на все 4хх и 5хх — то это какой-то треш.

    «MVP версия», некогда было, вот и один хендлер на все

    А так, ошибка где-то в core проявляется.

    в core кого, клиента или сервера?

    Да, потому что кроме формата данных, надо бы и бизнес-логику соблюдать :)
    В нем.
    5** — это то что клиент не может исправить.
    а 4** — что может.

    со стороны клиента? Для этого есть 422
    Ну пусть нравится 418 (хотя она не описывает суть, просто по сути ругается на клиента), только как же блин 4хх почти 5хх ? 4хх — это значит править клиенту, 5хх — значит править серверу. Они как бы ортогональны

    в core кого, клиента или сервера?

    Сервера конечно. Клиент в большинстве ж случаев — просто UI с кешированием.

    Для этого есть 422

    Нет, ее недостаточно.
    В MDN
    эта ошибка может возникнуть, если тело запроса содержит хорошо сформированный (т.е. синтаксически корректный) XML-документ, но семантически ошибочные XML-инструкции.

    Бизнес операция может требовать нескольких запросов, для формирования запроса на действие.
    То есть каждый запрос и семантически верен.
    А вот вся их последовательность, группа — неверна.

    И на core уровне срабатывает скажем какая-то валидация допустимости бизнес операции.

    И если бы клиент следовал правилам бизнес-валидации — он бы сформировал все корректно.

    хотя она не описывает суть, просто по сути ругается на клиента

    Где-то так, ругань немного присутствует — сервер отвечает — слышь, я не умею делать то что ты просишь

    4хх — это значит править клиенту

    Да. Разобраться в бизнес логике сервиса, и подправить запросы к нему

    5хх — значит править серверу

    Да

    хотя она не описывает суть,

    В маломальски сложном приложении никакие коды не описывают суть.
    Частенько с кодом ошибки идет еще и 2 сообщения в ответ
    одно для вывода пользователю
    другое для программиста, с кодом ошибки системы, с указанием чего-то что фронтендер может спросить у бекендера, или в технической документации

    убедили. Реально не знаю, каким кодом плеваться, если неправильный воркфлоу от клиента, а не конкретный запрос :)))

    Что вернуть в ответ, если получен пустой результат — пустой массив или 404?

    404 якщо не знайдено по айдішці конкретну сутність. У списках 404 не може бути, там тільки порожній масив.

    Дякую за активність, це мене мотивує писати далі, дуже радий, що контент був корисним!

    Чому HTTPS важливий для
    REST API

    Ну раз пошла такая малина, то можно было бы раскрыть такие темы как почему оптоволокно важно для рест апи или почему СУБД важно для рест апи. Или почему хттпс важно для рест апи, но для json API или json rpc api менее/более важно (по желанию).

    Как бы ты организовал взаимодействие в рамках рест-архитектуры между двумя башнями из властелина колец, при условии что твой транспорт это почтовые голуби?

    По хедерах в записці прикріпленій до голубів)

    Это все нагугливается за 5 минут и копипаститься из википедии. Где ответы на вопрос зачем это все, какие преимущества использования, конкретные примеры использования на проекте со сложным доменом.

    Тепер можна буде і українською нагуглити, шей швидше 5 хв і більше деталей.
    Якщо б я розписував абсолютно всі нюанси з прикладами, то це була б книжка, а не стаття. Якщо переваги та недоліки REST незрозумілі з контексту, то я можу додати окремий розділ, те ж саме про приклади, але я вважаю, що достатньо зрозуміло пояснив, чисто субʼєктивна думка.

    Сам REST запит складається з таких частин:

    Метод HTTP.
    Посилання.
    Заголовки.
    Параметри запиту.
    Тіло запиту.
    Змінні шляху.
    Версія HTTP.
    А REST відповідь в свою чергу містить:

    Статус код.
    Заголовки.
    Тіло відповіді (необовʼязково).
    Версія HTTP.

    Сам рест абсолютно параллелен хттп и никакак с ним не связан. Где в диссере Филдинга есть упоминания хттп методов, ресурсов-существительных, а не глаголов, правил построения красивых урлов?

    Дійсно, сам REST є архітектурним стилем і не прив’язаний виключно до HTTP.

    REST можна використовувати з будь-яким протоколом, але він часто реалізується через HTTP, оскільки це найпоширеніший протокол для веб-додатків. У дисертації Роя Філдінга не йдеться конкретно про HTTP-методи, але ми говоримо не суто про дисертацію, а про те, що можна застосувати в реальному житті. Філдінг описує REST як архітектурний стиль, що базується на принципах взаємодії між компонентами через стандартизовані інтерфейси та гіпермедіа.

    HTTP в цьому контексті просто виступає як реалізація принципів REST, — це загальноприйнята практика для веб-розробки.

    А что конкретно измениться, если я нарушу например 90 процентов из всех этих принципов? Например я буду использовать исключительно get/post и набор из кодов 200, 401, 403, 404, 500. Развалится ли вселенная если в урлах будут глаголы?

    А яким чином це суперечить принципам REST? Це просто поради як спростити собі та іншим життя при роботі з REST, загальноприйняті норми, але не обовʼязкові умови.

    Развалится ли вселенная если в урлах будут глаголы?

    Не розвалиться, але ви робите використання вашого API складнішим.
    Так, ви (або ваш proxy server) можете просто використовувати URL `/users/123` як key для кешування, та інвалідувати його на DELETE/PUT. З глаголами це буде зробити дещо важче.

    как минимум, какие-нибудь API гейтвеи, за которыми спрятаны ваши сервисы, могут реагировать совсем не так, как было бы желательно. Например, рессматривать запрос как неидемпотентный, если он POST, даже если он по сути идемпотентный и должен быть GET

    Круто, дякую. Детально і зрозуміло. По idempotency часто додають приклад GET, бо коли гетаєш сторінку 10 раз отримаєш той самий контент. Стосовно інших методів то там вже писати логіку треба

    Якщо буде натхнення з радістю почитав би від вас про tls, mtls як пов’язаний торік або типи авторизації

    Це ви ще не бачили, як в багатьох людей очі робляться квадратними після питання про доцільність тіла запиту в GET (плюси/мінуси, котрі проблеми вирішує, приклади в реальному житті).

    Або як зробити POST-запит ідемпотентим і в яких випадках це роблять.

    в параграфі про XSS два однакових фрагменти, навколо «Після екранування:»

    Схоже на доу відображається суто символ, а код символа трансформується в символ, гляну як можна виправити, дякую за уважність!)

    зберіг
    все по ділу, но головне в одному місці

    в інтернеті безліч подібного, але зазвичай там шось одне і для повного занурення в тему людині потрібно давати декілька посилань и шось між ними людина може і пропустити
    а тут все послідовно і з прикладами

    не прямо уж рокет-саенс з краемими моментами, но для формування базису у людини максимально повно

    В мене якраз була мета зібрати максимум корисної інформації в одному місці і все зрозуміло пояснити, щоб кожен міг не тільки прочитати і шось корисне для себе взяти, а й використати як шпаргалку/довідник при потребі.

    Підписатись на коментарі