REST API: проектируем контракт, а не эндпоинты
REST — это не «эндпоинты с JSON». Это набор соглашений о том, как описать ресурсы и операции над ними так, чтобы любой разработчик мог понять API без долгого чтения документации.
Контракт первичен
Хороший API начинается не с кода контроллера, а с контракта: какие ресурсы есть, какие у них поля, какие операции, какие ошибки. Контракт — это договор между бэкендом и его клиентами (фронтенд, мобильное приложение, партнёры).
Поменять контракт после релиза дорого: ломаются все клиенты. Поэтому сначала проектируем, потом кодим.
Базовые правила
Ресурсы — существительные, во множественном числе:
GET /posts — список
GET /posts/{id} — один
POST /posts — создать
PATCH /posts/{id} — частично обновить
DELETE /posts/{id} — удалить
Не глаголы в URL. POST /createPost — плохо. POST /posts — хорошо. Действие задаёт HTTP-метод, не путь.
Вложенность — для отношений:
GET /posts/{id}/comments
Глубже двух уровней лучше не уходить. /users/1/posts/2/comments/3/replies/4 — нечитаемо.
Коды ответов
200— успех с телом.201— ресурс создан.204— успех без тела (например, после DELETE).400— клиент прислал мусор.401— не авторизован.403— авторизован, но нельзя.404— нет ресурса.409— конфликт (например, уникальное поле).422— валидация не прошла.429— превышен лимит.5xx— это вы виноваты.
Не возвращайте 200 OK с {"error": "..."} в теле. Это ломает клиентам обработку ошибок.
Формат ошибок
Один формат на весь API. Например:
{
"message": "Validation failed",
"errors": {
"email": ["The email field is required."]
}
}
Когда формат единый — клиент пишет один обработчик ошибок, а не десять.
Версионирование
API меняется. Новые версии должны выходить, не ломая старые клиенты.
В URL — самый простой и распространённый вариант:
/api/v1/posts
/api/v2/posts
В заголовке — академически правильнее, но клиентам неудобно:
Accept: application/vnd.myapi.v2+json
В большинстве случаев — версионируйте через URL. Это понятнее всем.
Пагинация и фильтры
Никогда не отдавайте «весь список». Всегда с пагинацией.
GET /posts?page=2&per_page=20&status=published&sort=-published_at
-published_at — сортировка по убыванию. Это конвенция, и фронтенду удобно.
В ответе — метаданные:
{
"data": [...],
"meta": { "page": 2, "per_page": 20, "total": 184 }
}
Что часто забывают
- Идемпотентность.
PUTиDELETEдолжны быть идемпотентны: повторный вызов не ломает состояние. - Rate limiting. Без него один клиент может уронить ваш API.
- Документация. OpenAPI / Swagger — обязательны. Не описанный эндпоинт — несуществующий эндпоинт.
- Стабильность ответов. Не убирайте поля без выпуска новой версии. Лучше добавить новое, чем ломать старое.
Запомнить
- API — это контракт, проектируйте до кода.
- Существительные в URL, действие — в HTTP-методе.
- Один формат ошибок на весь API.
- Версионирование — с первого дня.
- Пагинация и rate limiting — не опция.
Также может быть интересно
Очереди в Laravel: Redis Queue, Horizon и Supervisor
Что такое фоновые задачи, зачем они нужны и как собрать надёжный воркер на Redis + Horizon + Supervisor.
Читать далее →