REST API: Загальний
20 питань · ~18 хв · Версія v3.0
Увійдіть, щоб продовжити
HTTP-методи й статус-коди, дизайн ресурсів, пагінація, кешування, ідемпотентність, автентифікація, помилки й API у Laravel.
- За спробу
- 20
- У пулі
- 100
- Проходжень
- 0
- Середній бал
- -
- Пройшли на 70%+
- -
Питання для підготовки
100 питаньPOST- створити ресурс (або виконати дію). Сервер сам обирає адресу нового ресурсу:POST /orders→201 CreatedзLocation: /orders/42.PUT- замінити ресурс цілком тим, що в тілі запиту. Поля, яких немає в тілі, вважаються видаленими чи скинутими.PATCH- частково змінити ресурс: лише передані поля.
PUT /users/42
{"name": "Оля", "email": "olia@example.com", "phone": null}
PATCH /users/42
{"phone": "+380501234567"}
Ідемпотентність - ключова відмінність, про яку питають:
PUTіDELETEідемпотентні: повторний однаковий запит лишає ресурс у тому самому стані. Їх можна безпечно повторити при обриві з'єднання.POSTне ідемпотентний: повтор створить друге замовлення.PATCH- залежить від змісту: «встановити phone» ідемпотентний, «збільшити лічильник на 1» - ні.GET,HEAD,OPTIONS- ще й безпечні: не змінюють стан узагалі.
На практиці:
- Багато API використовують лише
PATCHдля оновлень, бо клієнту рідко потрібно надсилати весь ресурс. - Для створення з повторами (платежі)
POSTроблять ідемпотентним через заголовокIdempotency-Key. - Дії, що не вкладаються в CRUD (
/orders/42/cancel), зазвичай оформлюють якPOSTна під-ресурс.
Проблема: клієнт відправив POST /payments, а відповідь не дійшла - таймаут, обрив мережі. Чи пройшов платіж? Повторити запит небезпечно (подвійне списання), не повторити - теж (платіж може не пройти).
Рішення: клієнт генерує унікальний ключ (UUID) для кожної логічної операції і передає його в заголовку. Повтор з тим самим ключем не виконує операцію вдруге, а повертає збережену відповідь першого виконання.
POST /payments
Idempotency-Key: 4f0f9c2e-8b1a-4c3e-9d5f-2a7b6c8d9e01
{"amount": 5000, "currency": "UAH"}
Реалізація на сервері:
- Отримати ключ і атомарно зарезервувати його (унікальний індекс у таблиці чи
SET NXу Redis) разом з ID користувача. - Якщо ключ новий - виконати операцію й зберегти статус і тіло відповіді.
- Якщо ключ уже є й операція завершена - повернути збережену відповідь.
- Якщо ключ є, але операція ще виконується (паралельний повтор) -
409 Conflict, щоб клієнт повторив пізніше. - Якщо той самий ключ прийшов з іншим тілом запиту -
422: це помилка клієнта, ключ використано повторно для іншої операції.
Деталі, про які питають:
- Ключ прив'язують до користувача, щоб чужий ключ не дав доступ до чужої відповіді.
- Термін зберігання ключів - зазвичай 24 години.
- Зберігати відповідь потрібно в тій самій транзакції, що й результат операції, інакше падіння між ними знову дасть подвійне виконання.
- Помилки валідації (4xx) зазвичай зберігають, а тимчасові збої (5xx) - ні, щоб повтор мав шанс пройти.
Саме так працюють Stripe і більшість платіжних API. IETF стандартизує заголовок Idempotency-Key в окремій специфікації.
Опублікований API - контракт з клієнтами, яких ви не контролюєте: мобільні застосунки старих версій, інтеграції партнерів. Їх не можна оновити одночасно з сервером.
Сумісні зміни (можна будь-коли):
- додати новий ендпоінт;
- додати необов'язкове поле в запит;
- додати поле у відповідь (клієнти мають ігнорувати невідомі поля - це варто прописати в документації);
- додати нове значення в перелік - обережно: клієнт зі строгою перевіркою enum може зламатися.
Несумісні (ламаючі): видалити чи перейменувати поле, змінити тип чи формат, зробити поле обов'язковим, змінити зміст коду відповіді, змінити поведінку за замовчуванням.
Версіонування для ламаючих змін:
- в URL -
/v1/orders,/v2/orders: найпростіше й найпомітніше; - в заголовку -
Accept: application/vnd.example.v2+jsonабо власний заголовок; - датою - як Stripe (
Stripe-Version: 2025-03-31): кожен клієнт закріплений на версії API на момент інтеграції, а сервер перетворює відповіді для старих версій.
Плавне виведення старого:
- Оголосити застарілість у документації й журналі змін.
- Додати заголовки:
Deprecation(RFC 9745) - що ресурс застарів,Sunset(RFC 8594) - дата, після якої він перестане працювати, іLinkна документацію з міграцією. - Моніторити використання старої версії за клієнтами й писати тим, хто ще на ній.
- Вимикати лише після дати й коли трафік зійшов нанівець.
Найкращий спосіб уникнути ламаючих змін - продумане проєктування: обгортки-об'єкти замість голих масивів у відповідях (до них можна додати поля), ідентифікатори-рядки, явні формати дат і грошей.
Коли ваш сервіс викликає інший (мікросервіс, партнерський API, внутрішній воркер), потрібно довести, який сервіс робить запит, і що запит не змінено по дорозі.
1. Статичний API-ключ / спільний секрет у заголовку - найпростіше:
Authorization: Bearer svc_billing_8f2a...
Мінуси: довгоживучий секрет, що зберігається в кількох місцях; викрадений ключ працює звідусіль; ротація болісна. Прийнятно для простих інтеграцій із ротацією й обмеженням за IP.
2. Підпис запиту (HMAC) - секрет не передається мережею, передається підпис:
X-Timestamp: 1760000000
X-Signature: hex(HMAC-SHA256(secret, method + path + timestamp + sha256(body)))
Отримувач обчислює підпис сам і порівнює у постійному часі (hash_equals). Мітка часу з коротким вікном (кілька хвилин) захищає від повторного відтворення. Так підписують вебхуки (Stripe, GitHub) і запити AWS (SigV4).
3. Взаємний TLS (mTLS) - обидві сторони пред'являють сертифікати:
- сервер перевіряє клієнтський сертифікат, виданий вашим внутрішнім центром сертифікації;
- ідентичність сервісу - у сертифікаті, а не в секреті в коді;
- RFC 8705 описує прив'язку OAuth-токенів до сертифіката: викрадений токен без приватного ключа клієнта непридатний.
Мінус - інфраструктура: власний CA, видача й ротація сертифікатів. Service mesh (Istio, Linkerd) роблять mTLS прозорим для застосунку.
4. Короткоживучі токени від центрального сервісу ідентифікації - OAuth 2.0 Client Credentials:
POST /oauth/token
grant_type=client_credentials&client_id=billing&client_secret=...&scope=orders:read
Сервіс отримує токен на хвилини з конкретними правами (scopes), отримувач перевіряє підпис і aud. У хмарах - ідентичності робочих навантажень (IAM-ролі, workload identity) без статичних секретів узагалі.
Як обрати:
- дві-три внутрішні інтеграції - підписані запити з ротацією секретів;
- багато сервісів, потрібні права й аудит - OAuth client credentials (у Laravel - Passport);
- мережа з нульовою довірою, високі вимоги - mTLS, часто разом із токенами.
Обов'язкове в будь-якому варіанті: найменші права для кожного сервісу, ротація секретів без простою (два дійсні ключі на час переходу), журнал викликів.
Запит складається з рядка запиту, заголовків і (необов'язково) тіла:
POST /api/orders HTTP/1.1
Host: shop.example.com
Accept: application/json
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...
Idempotency-Key: 8f14e45f-ceea-467f-a0d6-2a1e6c0c4f11
{"product_id": 42, "qty": 2}
- метод (
GET,POST,PATCH...) - що зробити; - шлях і рядок запиту - з яким ресурсом;
- заголовки - метадані: формат, автентифікація, кешування;
- тіло - дані (для
GETтіла зазвичай немає).
Відповідь - рядок статусу, заголовки, тіло:
HTTP/1.1 201 Created
Content-Type: application/json
Location: /api/orders/1057
Cache-Control: no-store
{"data": {"id": 1057, "status": "new"}}
Заголовки, які варто знати для API:
| Заголовок | Навіщо |
|---|---|
Content-Type |
формат тіла, яке надсилається |
Accept |
формат, який клієнт хоче отримати |
Authorization |
облікові дані (Bearer-токен) |
Location |
адреса створеного ресурсу (з 201) чи статусу операції (з 202) |
Cache-Control, ETag |
кешування й умовні запити |
Retry-After |
коли повторити (з 429, 503) |
X-Request-Id / traceparent |
наскрізний ідентифікатор для логів і трасування |
Типові помилки:
Content-Typeне відповідає тілу - сервер не розбере JSON, надісланий якtext/plain;- відсутній
Accept: application/jsonу запитах до Laravel - при помилці валідації замість JSON 422 прийде редирект на попередню сторінку; - статус 200 з
{"error": ...}у тілі - клієнти, проксі й моніторинг орієнтуються на код статусу, тож помилка має бути помилкою на рівні HTTP; - власні заголовки з префіксом
X-- застарілий звичай (RFC 6648); нові заголовки називають без нього.
Налагодження: curl -i показує заголовки відповіді, curl -v - і запиту; у браузері - вкладка Network.
Прочитати - ще не значить знати
20 питань, по одному на екран, ~18 хв. Після завершення - розбір кожної помилки з посиланням на питання.