[Перевод] Используйте всё богатство HTTP-кодов состояний
Если вы не специалист по REST, то, вероятно, в своих ответах постоянно используете одни и те же HTTP-коды, в основном 200, 404 и 500. Если применяется аутентификация, то, возможно, добавляются 401 и 403; если есть переадресации, то 301 и 302, но на этом, скорее всего, список заканчивается. Но спектр возможных кодов состояний гораздо шире и он может сильно улучшить семантику. Хотя во многих обсуждениях REST упор делается на сущностях и методах, применение подходящих кодов ответов о состояниях может повысить удобство вашего API.
201: Created
Многие приложения позволяют создавать сущности: аккаунты, заказы и так далее. В общем случае применяется HTTP-код состояния 200, и этого вполне достаточно. Однако код 201 более конкретен и подходит лучше:
HTTP-код ответа
201 Created
об успешном состоянии показывает, что запрос выполнен успешно и привёл к созданию ресурса. По сути, новый ресурс был создан до отправки этого ответа, а сам новый ресурс возвращается в теле сообщения, его местоположением становится или URL запроса, или содержимое заголовкаLocation
.— Веб-документация MDN
205: Reset Content
Аутентификация при помощи форм может быть успешной или неудачной. При неудачном выполнении обычно повторно отображается форма с очищенными полями.
И как раз для этого предназначен код состояния 205:
HTTP-код состояния
205 Reset Content
сообщает клиенту, что нужно сбросить визуализацию документа, то есть, например, очистить содержимое формы, сбросить состояние canvas или обновить UI.— Веб-документация MDN
428: Precondition Required
При использовании Optimistic Locking валидация при обновлении может быть неудачной, потому что данные уже были обновлены кем-то ещё. По умолчанию фреймворки (например, Hibernate) в таком случае выбрасывают исключение. В свою очередь, разработчики могут перехватывать его и отображать удобное информационное окно, просящее перезагрузить страницу и ввести данные повторно.
Давайте проверим код состояния 428:
Исходный сервер требует, чтобы запрос был условным. Это нужно для устранения проблемы «утерянного обновления», когда клиент при помощи GET получает состояние ресурса, изменяет его и помещает при помощи PUT обратно на сервер, в то время как третья сторона изменила состояние на сервере, что приводит к конфликту.
— Веб-документация MDN
Этот код чётко описывает случай конфликта при optimistic locking!
В RFC 6585 упоминается термин условный и показывается пример использования заголовка If-Match
. Однако в нём не показано, как конкретно достичь этого условия.
409: Conflict
Любопытно, что по поводу кода 409 написано следующее:
HTTP-код ответа состояния
409 Conflict
говорит о конфликте запроса с текущим состоянием сервера.— Веб-документация MDN
Он также применим в предыдущем случае, но более обобщённый. Например, типичным примером использования будет обновление уже удалённого ресурса.
410: Gone
Чаще всего, когда вы пытаетесь получить при помощи GET
ненайденный ресурс, сервер возвращает код 404. Но что, если ресурс существовал ранее, но теперь его нет? Интересно, что для конкретно этого случая есть альтернатива: об этом может сообщить семантика возвращаемого HTTP-кода. И именно поэтому используется 410.
HTTP-код ответа о клиентской ошибке
410 Gone
показывает, что доступ к целевому ресурсу уже отсутствует на исходном сервере и это состояние, скорее всего, будет постоянным.Если неизвестно, временное это состояние или постоянное, то нужно использовать код состояния 404.
— Веб-документация MDN
300: Multiple choices
Это может показаться натянутым выбором, но спецификация IETF соответствует данному случаю.
Приложения на основе HATEOAS имеют корневую страницу, которая становится точкой входа, позволяющей выполнять дальнейшую навигацию.
Например, вот какой ответ возникает при доступе к Spring Boot Actuator:
{
"_links": {
"self": {
"href": "http://localhost:8080/manage",
"templated": false
},
"beans": {
"href": "http://localhost:8080/manage/beans",
"templated": false
},
"health": {
"href": "http://localhost:8080/manage/health",
"templated": false
},
"metrics": {
"href": "http://localhost:8080/manage/metrics",
"templated": false
},
}
}
В этом местоположении отсутствует обычный ресурс. Сервер предоставляет множество ресурсов, каждый из которых имеет свой идентификатор. Это подходит для кода состояния 300:
[… ] сервер ДОЛЖЕН генерировать полезную нагрузку в ответе 300, содержащую список метаданных описания и ссылок на URI, из которого пользователь или агент пользователя может выбрать наиболее подходящий ему.
— IETF HTTP 1.1: Semantics and Content
Заключение
В общем случае конкретные состояния HTTP имеют смысл при наличии REST-бэкенда, доступ к которому выполняет JavaScript-фронтенд. Например, сброс формы (205) не имеет смысла, если страницу генерирует сервер.
Проблема этих кодов связана с семантикой: интерпретировать их можно по-разному. Зачем выбирать 409 вместо 428? В конечном итоге, это может быть вопросом интерпретации.
Если вы предоставляете публичный REST API, то у вас есть комбинация этих (и других) кодов, а также заголовки. Вам нужна подробная документация на все случаи, чтобы уточнить общую семантику для вашего конкретного контекста. Это не должно отталкивать вас от их использования, ведь они представляют собой богатое множество, из которого можно выбирать подходящие ответы.