Skip to content

Instantly share code, notes, and snippets.

@fomvasss
Last active August 7, 2024 12:31
Show Gist options
  • Save fomvasss/c1221b2464be94870f7f823c74520665 to your computer and use it in GitHub Desktop.
Save fomvasss/c1221b2464be94870f7f823c74520665 to your computer and use it in GitHub Desktop.
Проектирование API.txt
Аббревиатура REST расшифровывается как representational state transfer — «передача состояния представления» или, лучше сказать, представление данных в удобном для клиента формате. Термин “REST” был введен Роем Филдингом в 2000 г. Основная идея REST в том, что каждое обращение к сервису переводит клиентское приложение в новое состояние. По сути, REST — не протокол и не стандарт, а подход, архитектурный стиль проектирования API.
Любой ресурс имеет ID, по которому можно получить данные.
Сервер не хранит состояние — это значит, сервер не отделяет один вызов от другого, не сохраняет все сессии в памяти.
Методы POST и PUT должны возвращать обратно объект, который они изменили или создали, — это позволит сократить время обращения к сервису вдвое.
Возвращайте соответствующие http коды статуса в каждом ответе. Успешные ответы должны содержать следующие коды:
200 — для GET запроса и для синхронных DETELE и PATCH
201 — для синхронного POST запроса
202 — для асинхронных POST, DELETE и PATCH запросов
206 — для успешного частичного ответа на GET запрос
Уделите внимание ошибкам аутентификации и прав доступа:
401 Unautorized — пользователь не авторизован
403 Forbidden — доступ запрещен из-за недостатка прав
Дополнительные коды, указывающие на ошибки:
422 Unprocessable Entity — запрос корректный, но содержит неверные параметры
429 Too Many Requests — превышено лимит частоты подключений, попробуйте позже
500 Internal Server Error — Внутренняя ошибка сервера, можно обращаться к администратору
Headers
Рекомендуется при проектировании REST-сервисов явно указывать заголовки, в которых обозначен формат обмена данными:
Content-Type - формат запроса;
Accept - список форматов ответа.
Все в нижнем регистре
Используйте пути и имена только в нижнем регистре и только тире в качестве разделителя слов:
myservice-api.ru/users
myservice-api.ru/app-setups
Для атрибутов также желательно использование нижнего регистра, но необходимо использование символа подчеркивания в качестве разделителя, для совместимости с JavaScript. Например:
service_class: "first"
Форматируйте время по стандарту ISO8601
Прием и отправка даты/времени должны осуществляться только в UTC. Формат должен соответствовать ISO8601:
"finished_at": "2014-01-01T15:00:00Z"
Структурируйте информацию об ошибках
Создавайте последовательные и структурированные ответы при возникновении ошибок. Включайте идентификатор id типа ошибки, краткое описание message и url, указывающий на подробную информацию по данной ошибке:
HTTP/1.1 429 Too Many Requests
{
"id": "rate_limit",
"message": "Account reached its API rate limit.",
"url": "https://docs.service.com/rate-limits"
}
Документируйте формат сообщений об ошибках и все возможные типы ошибок, которые может получить клиент.
Действия над ресурсами, обычно, определяются стратегией CRUD и соответствуют HTTP-методам следующим образом:
GET /api/users — получить список пользователей;
GET /api/users/123 — получить указанного пользователя;
POST /api/users — создать нового пользователя;
PUT /api/users/123 — обновить все данные указанного пользователя;
PATCH /api/users/123 — частично обновить данные пользователя;
DELETE /api/users/123 — удалить пользователя.
Если ресурс существует только в контексте другого ресурса, то URL может быть составным:
GET /api/posts/9/comments — получить список комментариев к записи №9;
GET /api/posts/9/comments/3 — получить комментарий №3 к записи №9.
Когда действие над объектом не соответствует CRUD операции, то его можно рассматривать как составной ресурс:
POST /api/posts/9/like — отметить запись №9 как понравившуюся;
DELETE /api/posts/9/like — снять отметку «понравилось» с записи №9.
Действия по созданию и обновлению ресурсов должны возвращать ресурс
Методы POST, PUT или PATCH могут изменять поля ресурса, которые не были включены в запрос (например, ID, дата создания или дата обновления). Чтобы не вынуждать пользователя API выполнять ещё один запрос на получение обновлённых данных, такие методы должны вернуть их в ответе.
URL по сути является первичным ключом для единицы данных. То есть, например, вторая книга с книжной полки будет иметь вид /books/2, а 41 страница в этой книге — /books/2/pages/41. Отсюда и получается строго заданный формат. Причем совершенно не имеет значения, в каком формате находятся данные по адресу /books/2/pages/41 – это может быть и HTML, и отсканированная копия в виде jpeg-файла, и документ Word.
Рекомендуется при определении имени REST-сервиса использовать имена ресурсов во множественном числе. Такой подход позволяет добавлять новые REST-сервисы лишь расширяя имена уже существующих. Например, сервис /books вернёт нам список всех книг, /books/3 вернёт информацию о 3-ей книге, а сервис /books/3/pages вернёт все страницы 3-ей книги.
Фильтрация
Например, чтобы вывести все красные книги необходимо выполнить запрос:
GET /books?color=red
Сортировка
Например, чтобы вывести все книги, отсортированные по году публикации по убыванию и по названию по возрастанию нужно выполнить следующий запрос:
GET /books?sort=-year,+name
Пагинация
в REST API должен быть предусмотрен функционал пагинации. Реализуется он с помощью знакомых нам по SQL параметрам limit и offset. Например:
GET /books?offset=10&limit=5
Поммо того хорошим тоном является вывод ссылок на предыдущую, следующую, первую и последнюю страницы в хидере Link. Например:
Link: <http://localhost/api/books?offset=15&limit=5>; rel="next",
<http://localhost/api/books?offset=50&limit=3>; rel="last",
<http://localhost/api/books?offset=0&limit=5>; rel="first",
<http://localhost/api/books?offset=5&limit=5>; rel="prev"
Рекомендуется также возвращать общее количество ресурсов в хидере X-Total-Count.
Выбор полей ресурса
Для более удобного использования сервиса, для экономии трафика можно предоставить возможность управлять форматом вывода данных. Реализуется предоставлением возможности выбора полей ресурса, которые должен вернуть REST сервис. Например, если необходимо получить только id книг и их цвета, необходимо выполнить следующий запрос:
GET /books?fields=id,color
Версионность
Хорошим тоном является поддержка версионности REST API. Это позволит в дальнейшем легко расширять API, без обязательного внесения изменений в клиенты, которые уже пользуются им.
Имеются несколько подходов реализации версионности:
С использованием Accept хидера. В данном случае версия API указывается в Accept - Accept:text/v2+json
С использованием URI. В таком подходе версия API указывается прямо в URI - http://localhost/api/v2/books
Использование кастомного хидера. Можно использовать собственный хидер, который будет отвечать только за передачу версии API - API-Version:v2
Использование параметра запроса. Можно использовать параметр запроса для передачи версии API - /books?v=2
Обработка исключений
{
"code" : 1234,
"message" : "Something bad happened :(",
"description" : "More details about the error here",
“moreInfo”: “http:/localhost/api/v2/errors/1234”
}
// Full URL, with query string
$request->fullUrl()
// Just the path part of the URL
$request->path()
// Just the root (protocol and domain) part of the URL)
$request->root()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment