REST API Style Guide: URL и ресурсы
Правила именования URL, ресурсов и HTTP-методов в REST API.
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 /ordersPUT-- полная замена ресурса, идемпотентный. Пример:PUT /orders/{id}PATCH-- частичное обновление ресурса, неидемпотентный. Пример:PATCH /orders/{id}DELETE-- удаление ресурса, идемпотентный. Пример:DELETE /orders/{id}/items/{id}
4.1. Коды ответов
GET(один) -- успех:200 OK, ошибки:404GET(список) -- успех:200 OKPOST(создание) -- успех:201 Created+ заголовокLocation, ошибки:400POST(команда) -- успех:200 OKили202 Accepted, ошибки:400PUT-- успех:200 OK, ошибки:400,404PATCH-- успех:200 OK, ошибки:400,404DELETE-- успех: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)