Структурированные сообщения об ошибках для HTTP API
November 2, 2022
С тех пор как я начал работать над проектом Apache APISIX, я стараюсь улучшить свои знания и понимание REST RESTful HTTP API. Для этого я читаю и смотрю следующие источники:
- Книги. В данный момент я заканчиваю книгу API Design Patterns. Ожидайте обзор в ближайшее время.
- YouTube. Я бы рекомендовал канал ErikWilde. Хотя некоторые видео лучше других, все они посвящены API.
- IETF RFC. Большинство RFC не касаются API, но один добрый человек составил список тех, которые касаются.
Сегодня я хотел бы представить RFC "Problem Details for HTTP APIs", также известное как RFC 7807.
Проблема(ы)
Принципы REST предписывают использовать HTTP-статусы для общения. Для ошибок HTTP определяет два диапазона: ошибки клиента, 4xx, и ошибки сервера, 5xx.
Представьте себе банковский API, который позволяет осуществлять переводы. Он должен выдавать ошибку, если вы попытаетесь перевести больше средств, чем есть на вашем счете. Несколько HTTP-статусов могут подойти:
400 Bad Request: Сервер не может или не будет обрабатывать запрос из-за того, что воспринимается как ошибка клиента.402 Payment Required: Запрос не может быть обработан до тех пор, пока клиент не произведет оплату. Однако стандартного соглашения об использовании не существует, и разные организации используют его в разных контекстах.409 Conflict: Запрос конфликтует с текущим состоянием целевого ресурса.
Вот первая проблема: HTTP-статусы были разработаны для взаимодействия человека с машиной через браузеры, а не для взаимодействия машины с машиной через API. Поэтому выбор статуса, который однозначно соответствует конкретному случаю использования, редко бывает простым. Для справки, Мартин Фаулер, кажется, предпочитает 409 в нашем случае.
Независимо от статуса, вторая проблема касается полезной нагрузки ошибки или, точнее, её структуры. Структура не важна, если клиент и поставщик API управляются одной организацией. Даже если каждая из них разрабатывается отдельной командой, они могут согласовать её. Например, представьте мобильное приложение, которое вызывает собственный API.
Однако проблемы возникают, когда команда решает использовать сторонний API. В этом случае выбор структуры ответа имеет значение, так как она теперь считается частью контракта: любое изменение со стороны поставщика может сломать клиентов. Хуже того, структура, скорее всего, будет разной у разных поставщиков.
Следовательно, стандартизированная структура отчетов об ошибках:
- Обеспечивает единообразие среди поставщиков
- Повышает стабильность API
RFC 7807
RFC 7807 направлен на решение этой проблемы путем предоставления стандартизированной структуры ошибок.
Структура выглядит следующим образом:
RFC описывает поля:
"type"(string) - Ссылка URI [RFC3986], которая идентифицирует тип проблемы. Эта спецификация рекомендует, чтобы при разыменовании она предоставляла человекочитаемую документацию для типа проблемы (например, с использованием HTML [W3C.REC-html5-20141028]). Если этот член отсутствует, его значение предполагается равным"about:blank"."title"(string) - Краткое, человекочитаемое описание типа проблемы. Оно НЕ ДОЛЖНО изменяться от случая к случаю возникновения проблемы, за исключением целей локализации (например, с использованием активного согласования контента; см. [RFC7231, Section 3.4])."status"(number) - Статус ([RFC7231], Section 6), сгенерированный исходным сервером для данного случая проблемы."detail"(string) - Человекочитаемое объяснение, специфичное для данного случая проблемы."instance"(string) - Ссылка URI, которая идентифицирует конкретный случай проблемы. Она может или не может предоставить дополнительную информацию при разыменовании.
RFC предлагает следующий пример, когда недостаточно средств для осуществления банковского перевода.

Пример
Я использую один из своих существующих демо-проектов в качестве примера. Демо-проект выделяет несколько шагов для упрощения процесса эволюции ваших API.
На шаге 6 я хочу, чтобы пользователи регистрировались, поэтому я ограничиваю количество вызовов в временном окне, если они не аутентифицированы. Я создал специальный плагин Apache APISIX для этого. После того как количество вызовов достигло предела, он возвращает:
HTTP/1.1 429 Too Many Requests Date: Fri, 28 Oct 2022 11:56:11 GMT Content-Type: text/plain; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Server: APISIX/2.15.0 {"error_msg":"Please register at https:\/\/apisix.org\/register to get your API token and enjoy unlimited calls"}
Давайте структурируем сообщение в соответствии с RFC 7807.
Заключение
RFC 7807 не только помогает разработчикам клиентов. Это огромная помощь для разработчиков API, так как он предоставляет быстрые рекомендации, чтобы избежать изобретения велосипеда в каждом проекте.
Пойдите дальше:
Оригинальная публикация на A Java Geek 30 октября 2022 года