REST API Style Guide: URL и ресурсы

Правила именования URL, ресурсов и HTTP-методов в REST API.

REST API URL ресурсы

REST API URL ресурсы: 1. Общие принципы

REST API URL ресурсы — - Предсказуемость -- разработчик, знающий один эндпоинт, должен угадать остальные

  • Единообразие -- одни и те же правила для всех контекстов и сервисов
  • Читаемость -- URL читается как фраза на английском: GET /orders/{id}/items = "get order's items"
  • Стабильность -- URL -- часть публичного контракта; изменение = breaking change

2. Формат URL-пути

2.1. Только строчные буквы

/api/v1/order-items     -- правильно
/api/v1/OrderItems      -- неправильно
/api/v1/order_items     -- неправильно

2.2. Разделитель слов -- дефис (kebab-case)

/api/v1/delivery-addresses   -- правильно
/api/v1/delivery_addresses   -- неправильно
/api/v1/deliveryAddresses    -- неправильно

2.3. Без завершающего слеша

/api/v1/orders       -- правильно
/api/v1/orders/      -- неправильно

2.4. Без расширений файлов

/api/v1/orders       -- правильно
/api/v1/orders.json  -- неправильно

2.5. Без глаголов в пути (за исключением action-эндпоинтов, см. раздел 7)

GET /api/v1/orders          -- правильно
GET /api/v1/getOrders       -- неправильно
POST /api/v1/orders         -- правильно
POST /api/v1/createOrder    -- неправильно

2.6. Служебные эндпоинты -- вне /api/v1/...

Эндпоинты инфраструктуры не являются частью бизнес-API и живут отдельно:

  • /health или /api/health -- проверка работоспособности
  • /ready -- готовность принимать трафик (Kubernetes readiness)
  • /info -- метаинформация о сервисе (версия, окружение)
  • /metrics -- метрики (Prometheus, Micrometer)

Служебные эндпоинты не требуют аутентификации (или защищены отдельно через management-порт) и не версионируются.


3. Ресурсы: имена существительные во множественном числе

3.1. Коллекция -- всегда множественное число

/api/v1/orders              -- коллекция заказов
/api/v1/orders/{id}         -- конкретный заказ
/api/v1/users               -- коллекция пользователей
/api/v1/users/{id}          -- конкретный пользователь

3.2. Единственное число НЕ используется для коллекций

/api/v1/orders       -- правильно
/api/v1/order        -- неправильно

3.3. Singleton-ресурсы -- единственное число

Если ресурс существует ровно в одном экземпляре в контексте родителя:

/api/v1/users/{id}/profile       -- профиль конкретного пользователя (один на пользователя)
/api/v1/settings                     -- глобальные настройки (один на приложение)

3.4. Имя ресурса -- доменный термин

Используйте Ubiquitous Language из глоссария. Если в домене сущность называется Order -- в URL orders, не purchases, не transactions.

  • Order -- /orders, не /purchases, /transactions
  • OrderItem -- /items (вложенный), не /lines, /rows, /products
  • DeliveryAddress -- /delivery-addresses, не /addresses, /shipping-info
  • Payment -- /payments, не /charges, /billing

4. HTTP-методы и семантика

  • GET -- чтение без побочных эффектов, идемпотентный. Пример: GET /orders/{id}
  • POST -- создание ресурса или выполнение команды, неидемпотентный. Пример: POST /orders
  • PUT -- полная замена ресурса, идемпотентный. Пример: PUT /orders/{id}
  • PATCH -- частичное обновление ресурса, неидемпотентный. Пример: PATCH /orders/{id}
  • DELETE -- удаление ресурса, идемпотентный. Пример: DELETE /orders/{id}/items/{id}

4.1. Коды ответов

  • GET (один) -- успех: 200 OK, ошибки: 404
  • GET (список) -- успех: 200 OK
  • POST (создание) -- успех: 201 Created + заголовок Location, ошибки: 400
  • POST (команда) -- успех: 200 OK или 202 Accepted, ошибки: 400
  • PUT -- успех: 200 OK, ошибки: 400, 404
  • PATCH -- успех: 200 OK, ошибки: 400, 404
  • DELETE -- успех: 204 No Content, ошибки: 404

Полный перечень допустимых кодов ошибок -- в разделе 13.6.

4.2. GET никогда не изменяет состояние

GET /api/v1/orders/{id}/cancel    -- НЕПРАВИЛЬНО (побочный эффект через GET)
POST /api/v1/orders/{id}/cancel   -- правильно

5. Вложенность ресурсов

5.1. Максимум два уровня

/api/v1/orders/{id}/items                       -- правильно (2 уровня)
/api/v1/orders/{id}/items/{id}                  -- правильно (2 уровня + id)
/api/v1/users/{id}/orders/{id}/items/{id}       -- неправильно (3 уровня)

Если нужен третий уровень -- вынесите ресурс на верхний уровень с фильтром:

GET /api/v1/items?orderId={id}                  -- альтернатива глубокой вложенности

5.2. Вложенность отражает принадлежность

Используйте вложенность только когда дочерний ресурс не существует вне родителя:

/api/v1/orders/{id}/items            -- OrderItem не существует без Order
/api/v1/users/{id}/orders            -- допустимо, но лучше /orders?userId={id}

5.3. Идентификатор -- в пути, не в теле запроса

PUT /api/v1/orders/{id}              -- id из пути
PUT /api/v1/orders  { "id": "..." } -- неправильно

5.4. Формат идентификатора в пути -- {id}

Path-переменная для идентификатора всегда называется {id}. Контекст (имя ресурса в предыдущем сегменте) устраняет неоднозначность:

/api/v1/orders/{id}              -- правильно
/api/v1/orders/{orderId}         -- неправильно (избыточно, имя ресурса уже в пути)
/api/v1/orders/{id}/items/{id}   -- правильно (первый {id} = order, второй = item)