Принципы построения синхронного API

Пример синхронного API

Приложение отправляет запрос получателю и останавливает работу, пока ждёт ответа. Такой подход применяют, если нужно сохранить порядок вызовов систем.

  1. Уровень 0
    Легаси

    Используем XML, единственный URI и HTTP-метод — обычно POST.

  2. Уровень 1
    Ресурсы

    Каждому ресурсу отдельный эндпоинт, можно перейти на JSON.

  3. Уровень 2
    HTTP-глаголы

    Используем правильные HTTP-методы и статус-коды, поддерживаем фильтрацию, пагинацию, поиск, сортировку и версионирование.

Цель — достичь 2 уровня на всех канонических API.


Построение URI

https:// 
схема
api.leroymerlin.ru / 
хост
domain / 
домен
application 
система
/ v1 / 
версия
products?
продукт
siteId=12&statusCode=active
параметры запроса

Используем kebab-case для URL и camelCase для параметров и атрибутов.

  • У каждого ресурса свой эндпоинт.
  • Название ресурса всегда во множественном числе.
  • Если ресурс относится к другому, используем вложенность.

    /customers/{id}/addresses все адреса конкретного кастомера

  • Максимальная вложенность — 1.

    /suppliers/{id}/products/{id}/media/{id} слишком глубоко

  • Можно использовать единственное число там, где других таких же предметов быть не может.
  • /delivery/v1/products не бывает иных обьектов delivery

Хорошие примеры

/customers все кастомеры
/customers/{id}/addresses все адреса конкретного кастомера
/products?supplierId={supplierId} список продуктов по поставщику
/products/{id} детали определённого продукта
/products/{id}/media список медиа одного продукта

Умеренная гранулярность.

Не надо возвращать информацию, которую не спрашивали.

  /clients/1/address
  {
    “road”: “121 rue Chanzy”,
    “city”: “Hellemmes”,
    “country”: “France”,
    “age”: 22 — возраст здесь лишний
  }

Используем суррогатные ключи правильно.

Суррогатный ключ — это ключ, искусственно сгенерированный системой. Не путать с первичным ключом базы данных. Ещё бывают натуральные ключи, сформированные из атрибутов, существующих в реальной жизни.

В REST API, вместо первичных ключей базы данных, лучше использовать натуральные ключи — если БД поменяется, у нас могут быть проблемы с интеграцией, да и вообще это не секьюрно.

Хорошие примеры

/some-resource?tag=green натуральный ключ green понятен пользователям
/customer/0012345 кастомер ID — суррогатный ключ для этого API

Плохие примеры

/some-resource?tag=1 вернуть всё с тегом green через его id «1»
/customer/23dde7-e89b-12d3-a456-4265 кастомер ID это UUID, сгенерированный БД


HTTP-методы

  • GET получить
  • POST создать
  • PUT перезаписать
  • PATCH частично обновить
  • DELETE удалить
  • OPTIONS вернуть все HTTP-методы, доступные для эндпоинта

Когда что-то не подходит, используем

  • POST метод
  • action-глаголы
  • паттерн /collections/{resource}:{action}

    Пример

    POST /users/123:subscribe

URL параметры запросов

Заголовки

Содержит технические параметры или элементы контекста.

Content-Type: application/json
ADEO-BU-CODE: 10

Path-параметры

Эти параметры — часть URL. С их помощью можно понять, к какому ресурсу мы обращаемся.

/product/{id}/stocks

Query-параметры

Позволяют фильтровать и сортировать запросы.

Хорошие примеры

/products?q=Luke+man поиск продукта по тексту
/products?storeId=35 фильтрация продуктов по параметру магазина 35
/products?sort=name&desc=age,id сортировка по возростанию name и убыванию age, а затем id.


Пагинация

  • Пагинация по номеру страницы

    ?page=2&perPage=100

  • Пагинация по курсору
    ?limit=25&before=ZDMyNz6yORI3OTLo

    Не стоит хранить курсоры: они быстро становятся невалидными из-за вставки или удаления элементов.

  • Пагинация через оффсет & лимит

    ?limit=25&offset=50

  • Пагинация через временные метки
    ?limit=25&since=1364849754

    В качестве ключа для пагинации по временным меткам используем Unix timestamp.


Ответ: Общие правила

  • Структура ответа HTTP не должна зависеть от структуры БД
  • Все поля должны быть понятны с бизнес-точки зрения
  • Все наименования полей должны быть простыми, интуитивными и согласованными
  • Лучше не использовать технические термины и специфические термины систем.

Ответ: Статус коды

Все методы

  • Для всех эндпоинтов необходимо возвращать статус-коды.
  • Каждый сервис потенциально должен уметь возвращать 500.
  • Каждый сервис, который требует минимум один обязательный параметр на вход, должен уметь возвращать 400 с описанием.
  • Каждый секьюрный сервис должен уметь возвращать 401.

GET

  • Если данных нет, каждый сервис должен возвращать 404.
  • Каждая коллекция должна вернуть 200, если возвращается полностью.
  • Каждая коллекция должна вернуть 206, если возвращается частично.

204 или 404

Есть небольшой спор: какой код возвращать, когда URL корректный, но информация не найдена? Если информация запрашивалась по ключу, мы рекомендуем возвращать 404, если информация не найдена после фильтрации или поиска по параметрам — 204.

POST

  • Возвращаем 201 после создания ресурса.

PUT & PATCH:

  • Возвращаем 200 после обновления ресурса.

DELETE

  • Возвращаем 204 после успешно удалённой информации.

Ответ: Коды ошибок

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

Один из популярных форматов описания ошибок JSON-API:

{
  "errors": [{
    "code": "ERR-01234",
    "title": "OAuth Exception",
    "details": "Session has expired at unix time 1385243766.", 
    "links": {
      "about": "http://example.com/docs/errors/#ERR-01234"
    }
  }]
}  

Кусок кода в формате сваггера с описанием кода ответа и кода ошибок:

{ 
  Responses:
    ”200”:
      description: mySuccessResponse
  Schema:
    type: array
  Items:
    $ref: “#/definitions/Pet”,
    “400”: 
      description: Invalid status value
}


Ответы: Формат данных

E.164 – Телефонный номер

[+][код страны][код местности][местный номер]

  • + — знак плюса
  • код страны — международный код страны
  • код местности — код местности без 0 в начале
  • местный номер — местный номер телефона

ISO 639 – Язык

  • eng – Английский
  • fra – Французский
  • rus – Русский

ISO 3166-1 — Язык

  • Russia (Russian Federation) Россия RU RUS 643
  • France Франция FR FRA 250
  • China Китай CN CHN 156

ISO 8601 – Дата

  • YYYY-MM 2020-06
  • YYYYMMDD 20200602
  • YYYY-MM-DDThh:mm:ss±hh 2020-06-02T15:22:00+00:00

ISO 4217 — Деньги

  • EUR 978 – Евро
  • USD 840 – Доллар США
  • KZT 398 – Тенге
  • BYN 933 – Беларусский Рубль

UCUM – Меры измерения

Все меры измерения в UCUM specification.


Предложить улучшения
Последнее изменение 25.05.2022: Merge remote-tracking branch 'liga/master' (#51) (158d622)