Backend

REST API: проектируем контракт, а не эндпоинты

Никита Литвяков
Никита Литвяков
Senior PHP / Laravel Backend Developer
Обложка статьи: 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 — не опция.
#Архитектура #Backend #API
Поделиться:

Также может быть интересно