Еще одна практика разработки REST API

Kate

Administrator
Команда форума
Эта статья предназначения для специалистов, уже имеющих опыт разработки REST API. Большинство уже знакомы с лучшими практиками разработки REST API, но некоторые советы и популярные приемы могут оказаться не столь хорошими … Предлагаю посмотреть, как можно улучшить даже самые хорошие практики для интерфейсов, замыкающихся на объекты реляционных моделей.

Определения​

/users: – маршрут коллекции

/user: – маршрут объекта

Получить пользователя по номеру телефона, почты, СНИЛС и т.д.​

Если хотите получить один объект по id или ошибку 404, сделайте так …

/users/{id}:

Если хотите получить один объект по прочим уникальным ключам или ошибку 404, сделайте так …

/user: … parameters: phone, email, snils, login etc.

Если нужно получить сравнительно небольшой список по критериям выборки, то так …

/users: … parameters: …

Если список очень большой и получение предполагается в несколько итераций, то с помощью выделенной операции …

/users/list: … parameters: lastKey, limit.

Напоминание, используйте параметр fields для подрезки трафика, забирайте только нужные данные.

Не более одного параметра в маршруте​

Если у вас не составной ключ, что для реляционной модели редкая редкость, то так …

Плохо:

/orders/{orderId}/items/{itemId}:

Хорошо:

/orders/items/{itemId}:

Делайте дружественный API​

Если к вам будут ходить разные системы и каждая система хочет работать со своим ключом объекта – сделайте дружественное API. Полиморфность идентификатора реализуется так:

/users/{id}:
parameters:
- name: id
description: Идентификатор объекта
in: path
required: true
schema:
type: string
- name: idType
description: Тип идентификатора
in: query
schema:
type: string
default: sys
enum: [sys, …]

Избегайте ложных вложенностей​

Предположим, есть магазин, в котором покупатели оставляют заказы, сразу хочется сделать такой маршрут …

/customers/{id}/orders: – заказы покупателя.

На самом деле заказ является центральной сущностью, а клиент, организация — это её атрибуты.

Плохо:

/customers/{id}/orders:

/organizations/{id}/orders:

/contracts/{id}/orders:

Хорошо:

/orders: … parameters: customerId, organizationId, contractId (лучше даже массивом).

Еще пример, представим, что вам надо описать отношение учитель – ученик. Как правило, связь двух равноправных сущностей бывает нагружена дополнительными атрибутами, поэтому …

Плохо:

/teachers/{id}/students:

/students/{id}/teachers:

Хорошо:

/teacher-student-relations: … parameters: teacherId, studentId (лучше даже массивом).

Используйте вложенность только для специфических случаев​

  1. Для доступа к вложенным коллекциям.
  2. Для non-CRUD операций.
  3. Для вынесенных операций, чтобы изолировать потребителя от остального API. Пример, установить лимит для пользователя …
PATCH /users/{id}/limit:

Отказывайтесь от объектных методов, задействуйте методы коллекций по максимуму​

И наконец совет, который очень упростит пользование API с фронта и при взаимодействии систем. Используя его, вы предотвратите: бессмысленную и беспощадную бомбардировку серверов запросами, чудовищную перегрузку баз данных, порадуете разработчиков UI (им часто требуется: замена, добавление или удаление списка за одну операцию). В итоге, учитывая требования к быстродействию, нагрузке, снижению трафика и возможные потребности для разработки UI получим такую практику:

GET коллекции

Операция GET /users/{id}: вовсе не обязательна, пользуйтесь /users: … parameters: id, etc.

DELETE коллекции

Принимайте на вход массив идентификаторов и удаляйте объекты пачками.

POST (PUT) коллекции

Передавайте набор объектов для массовой вставки (обновления). Объектная версия операции вовсе не обязательна.

PATCH коллекции

Передавайте набор свойств объектов для массового обновления. Используйте частичное заполнение объекта, точнее: id объекта + обновляемый набор свойств.

Чтобы полноценно реализовать совет вам потребуется конструкция allOf.

Создайте base-объект только с набором предметных свойств, без required. Далее наследованием создайте:

  • для POST – новый объект с секцией required, на основе base-объекта.
  • для PUT (если нужен) – новый объект + id, на основе post-объекта.
  • для PATCH - новый объект + id, на основе base-объекта.
  • для GET - новый объект + технические свойства + обогащения, на основе base-объекта.
Можно сократить количество объектов на 2 (PUT, PATCH), если в базовый сразу добавить id (в POST будет 0 или ””).

 
Сверху