REST API за который не стыдно

Как правильно проектировать API? На самом деле нет ни одной официальной спецификации, которая отвечает на этот вопрос. Но, тем не менее, хорошо разработанный API прост в понимании, использовании и обслуживании. Он должен соответствовать согласованным стилевым решениям, включать встроенные механизмы безопасности для аутентификации и шифрования данных и надежно обрабатывать большие объемы трафика. Ниже попробую дать несколько советов, как этого достичь.

Дизайн URI

В архитектуре RESTful API URL-адреса обычно служат для представления ресурсов (объектов), в то время как методы HTTP (такие как GET, POST, PUT и DELETE) отражают операции, которые можно выполнять над этими ресурсами. Такой подход к разработке акцентирует внимание на состоянии и представлении ресурсов, а не на конкретных действиях.

Объект должен быть существительным

В процессе разработки API URL (Uniform Resource Locator) обычно выступает в роли ресурса, который является объектом HTTP-глагола. Согласно принципам RESTful проектирования, URL-адреса должны быть существительными, а не глаголами, поскольку они обозначают набор «ресурсов» или отдельный экземпляр, а не действие.

# Плохо
/getAllCars
/createNewCar
/deleteAllRedCars

# Хорошо
/allCars
/newCar
/allRedCars

URL-адреса в множественном числе

При формировании URL-адресов настоятельно рекомендуется использовать форму множественного числа. Это связано с тем, что такие адреса обычно представляют собой коллекции ресурсов, а использование множественного числа позволяет сохранить единообразие и ясность в их структуре.

Даже если вы указываете на один конкретный ресурс, использование множественного числа остается предпочтительным. Например, /users/123 будет представлять пользователя с идентификатором 123, что обеспечит согласованность всех URL-адресов. Если ресурсы имеют иерархическую структуру, то URL-адрес должен отражать эту взаимосвязь. Например, /users/123/posts может означать коллекцию записей, созданных пользователем с идентификатором 123.

Избегайте сложных вложенных URL-адресов

Часто ресурсы требуют многоуровневой классификации, что приводит к созданию сложных и запутанных URL-адресов. Например, чтобы найти статьи конкретной категории определённого автора, вам может потребоваться следующий путь:

GET /authors/12/categories/2

Очень субъективно, но по мне лучше когда используются параметры запросов.

GET /authors/12?categories=2

Не создавайте беспорядочный API. Не следует помещать все функции в один endpoint. Если вам сложно распределить функции по разным URL-адресам, вы можете обратиться и придерживаться принципов DDD.

  1. Системы маленькие по размеру
  2. Системы очень простые
  3. Есть кристально чёткие границы систем

Коды состояния

На каждый запрос клиента сервер должен отвечать кодом состояния HTTP и соответствующими данными. Код состояния HTTP представляет собой трехзначное число, которое можно разделить на пять категорий:

  • 1xx: Информация
  • 2xx: Успех
  • 3xx: Перенаправление
  • 4xx: Ошибки клиента
  • 5xx: Ошибки сервера

Эти пять категорий включают более 100 кодов состояния, которые охватывают большинство возможных ситуаций. Каждый код состояния имеет стандартное или общепринятое значение, что позволяет клиенту понять, что произошло, просто взглянув на код. Поэтому сервер должен возвращать максимально точный код состояния.

Не буду описывать здесь все эти коды. Вы их можете с легкостью нагуглить.

Ответы сервера

Вы помните, что ответ должен быть JSON, в редких случаях XML. Не забываем использовать для заголовка Content-Type и он должен быть application/json. Клиент также должен указать, что он принимает ответы JSON, установив заголовок Accept в своем запросе:

GET /orders/2 HTTP/1.1
Accept: application/json

Код состояния должен четко указывать на результат запроса. В случае возникновения ошибок следует использовать соответствующие коды состояния, а более подробная информация содержится в тексте ответа.

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "error": "Invalid payload.",
}

Используйте HAL (языка гипертекстовых приложений)

HAL — это широко известный формат гипермедиа, который наглядно демонстрирует связи между различными ресурсами.

{
  "id": 1,
  "name": "Example",
  "links": {
    "self": "http://api.example.com/resource/1",
    "related": "http://api.example.com/resource/2"
  }
}

Верните созданный ресурс но не возвращайте содержимое

Отвечайте только кодом 201 Created или 204 No Content с заголовком Location, не предоставляя информацию о самом ресурсе. Такой подход минимизирует объём передаваемых данных и даёт клиенту возможность решить, стоит ли запрашивать ресурс позже.

HTTP/1.1 201 Created
Location: /resources/123

Документирование API

Это очень важный момент, который часто упускают из виду, особенно если API не является общедоступным. Не стоит недооценивать Swagger или ReDoc. Лично мне больше по душе ReDoc.

Версионность

API — это как живой организм: в нём постоянно появляются новые функции, а устаревшие исчезают. Как только вы теряете обратную совместимость, важно зафиксировать версию продукта. Особенно если ваше API является публичным.