Skip to content
Anton Korniychuk edited this page Mar 21, 2016 · 18 revisions

Main API Standard

Этот документ есть основным соглашение REST-api в компании onCreate

Оглавление

Основные положения

  • Любое api всегда имеет версию. Версия задается префиксом //v*/ в начале url. Пример https://api.infitting.com/v1/...
  • Любое API должно использовать протокол https
  • Во всех примерах, а так же в документации к запросам префикс версии не указывается.
  • Любое API должно быть задокументировано. Для документации предпочтительно использовать Postman
  • Все запросы должны содержать проверки безопасности. К примеру пользователь может редактировать только СВОИ статьи, удалить только СВОИ статьи, а смотреть может ВСЕ статьи.
  • Сервер не использует сесии и не хранит никаких временных данных о сеансе. Все необходимое для выполнения запроса клиент должен указать в запросе.

Формирование URL

В примере используется сущности:

  • Пользователь(user)
  • Статья(article) которая принадлежит пользователю
  • Комментарий(comment) который принадлежит статье

Основные правила именования сущностей в url

  • url для корневой сущности (например "пользователь") /users/<id:\d[\d,]*>
  • url для вложенной(1-й уровень) сущности(например "статья") /users/<user_id:\d[\d,]*>/articles/<id:\d[\d,]*>. Важные моменты:
    • у пользователя id переименован в user_id
    • у последней сущности первичный ключ всегда должен быть назван id
  • url для дальнейших вложенностей(2-й и глубже) может иметь сформирован двумя способами
    • /users/<user_id:\d[\d,]*>/articles/<article_id:\d[\d,]*>/comments/<id:\d[\d,]*>
    • /articles/<article_id:\d[\d,]*>/comments/<id:\d[\d,]*> (предпочтительно) В этом случае первая вложенность опускается, и ссылка становится короче.
  • Если в url больше одного первичных ключей, и последний на 100% точно идентифицирует сущность сам по себе, то все предыдущие можно передавать как 0. (сущностей с pk==0 не у нас не бывает). Пример: PUT /users/2/articles/13 и PUT /users/0/articles/13 должны всегда работать одинаково, при условии что в сущности "статья" id на 100% идентифицирует сущность.
  • Если сущность состоит из нескольких слов, слова записываются через тире. Пример super-user. Без верблюжьей нотации и без подчеркиваний _.
  • Все сущности должны быть названы во множественном числе. Примеры: users, articles, comments
  • Если часть url обозначает действие, а не название сущности, нужно писать в единственном числи. Пример POST /articles/0/comments/1/like, POST /articles/0/comments/1/spam. Где like и spam обозначает 'поставить метку' лайк и спам соответственно.

HTTP глаголы

Правило одно: можно использовать любые глаголы стандарта http 1.1, и нельзя придумывать свои.

Некоторые HTTP-методы (например: HEAD, GET, OPTIONS и TRACE) определены как безопасные, это означает, что они предназначены только для получения информации и не должны изменять состояние сервера. Другими словами, они не должны иметь побочных эффектов, за исключением безобидных эффектов, таких как: логирование, кеширование, показ баннерной рекламы или увеличение веб-счетчика.

Рекомендуемые глаголы:

  • GET - Получить данные | безопасный | Тело: Запрос не имеет. Ответ может иметь, может не иметь.
  • POST - Создание сущности. А так же ситуации когда другие запросы не подошли. В ответ зачастую приходят основные поля сущности | Тело: Запрос может иметь, может не иметь, Ответ: может иметь, может не иметь
  • PUT - Обновить сущность, в теле указываются обновляемые поля | Тело: Запрос - должен иметь, Ответ: должен иметь(обновленная сущность с такими же полями как при POST)
  • DELETE - Удалить сущность | Тело: запрос - не имеет, ответ - может иметь, но если все хорошо - не имеет
  • OPTIONS - Вернет в заголовках список методов которыми можно обращаться к этому url. Нужно для реализации крос-доменных запросов в браузерах. Для mobile-разработки не нужен.

Могут так же использоваться глаголы: (но это на будущее, пока что не используются)

  • HEAD - Получить данные, то же самое что GET, но без тела. | безопасный | Тело: Запрос не имеет. Ответ не имеет.
  • PUTCH - обновить без замены
  • LINK - установить связь между сущностями
  • UNLINK - разорвать связь между сущностями

Экшены(action) по умолчанию

Экшен - это действие которое выполняется над сущность.

Примеры основных экшенов для пользователя

экшен метод url описание
index GET /users Получить список все(или отфильтрованных) пользователей
view GET /users/4 Получить одного пользователя
create POST /users Создать пользователя(регистрация)
update PUT /users/4 Обновить одного пользователя
delete DELETE /users/4 Удалить одного пользователя

Примеры дополнительных экшенов

экшен метод url описание
login POST /users/login Аутентификация. Пример тела: login=admin&password=123321. Пример ответа {id: ...(id пользователя), token:...(bearer token)}
logout POST /users/logout Выйти. Должен удалится token под которым пользователь послал этот запрос

Примеры основных экшенов для статьи

экшен метод url описание
index GET /users/4/articles Получить список статей принадлежащих пользователю id:4
index GET /users/0/articles Получить список ВСЕХ статей. Возможно с фильтрами(в query параметрах)
view GET /users/0/articles/5 Получить статью в id:5
create POST /users/4/articles Создать статью принадлежащую 4-му пользователю
update PUT /users/0/articles/5 Обновить статью с id:5
delete DELETE /users/0/articles/5 Удалить статью 5

Формат общения

Формат тела запроса ОБЯЗАТЕЛЬНО должен быть указан в заголовке Content-Type

Термины:

  • Сущность - JSON объект. Возвращается когда есть запрос на обработку конкретного элемента (к примеру /users/5)
  • Коллекция - Массив сущностей.

Запрос

Тело запроса должно быть в формате:

  • json - Content-Type: application/json
  • x-www-form-urlencode - Content-Type: application/x-www-form-urlencoded
  • multipart/form-data - Content-Type: multipart/form-data
  • xml (по умолчанию отключен) - Content-Type: text/xml

Ответ

Формат ответа. Клиент может запросить ответ в одном из определенных форматов, но указываться клиентом в заголовке Accept.

  • json - application/json
  • xml - text/xml

Если в ответе если приходит сущность, она ни во что не вложена. Никаких { data: ..., errors: ...}

Поля ответа бывают

  • Основные - это поля которые приходят по умолчанию. Можно запросить что бы они приходили не все, а только часть из них. Для этого нужно в query-параметре fields перечислить нужные поля через запятую. Пример ?fields=name,surname,avatar
  • Дополнительные - Это поля которые по умолчанию не приходя. Зачастую вычисление значений этих полей требует дополнительных ресурсов, или они имеют объемное значение. По этому они и не приходят по умолчанию. Их можно запросить query-параметром: ?expand=article_count,text.

Рекомендации по запросу полей:

  • Используйте на максимум параметр fields. Особенно на часто выполняемых запросах. Если у сущности 20 полей, а вам реально нужно только 3. То указание в fields только три этих поля - позволит значительно сэкономить трафик, и быстрее получить ответ сервера, что ускорит общую работу приложения.
  • Не используйте без надобности дополнительные поля (expand). Это может привести к перегрузке сервера.

Пагинация

У любой коллекции есть пагинация. Всегда будут заголовки пагинации:

    X-Pagination-Total-Count: 1000 - общее кол-во элементов
    X-Pagination-Page-Count: 50 - кол-во страниц
    X-Pagination-Current-Page: 1 - текущая страница
    X-Pagination-Per-Page: 20 - Кол-во на странцу
    Link: <http://localhost/users?page=1>; rel=self,
          <http://localhost/users?page=2>; rel=next,
          <http://localhost/users?page=50>; rel=last

Что бы задать параметры пагинации используются get параметры:

  • ?per-page=20 - кол-во на страницу
  • ?page=2 - страницы
  • ?page-from-id=30 - максимальный номер первичного ключа с которого считать страницы. Этот параметр нужен что бы если между запросами 2 страниц(page) появится новая запись(или удалится), то что бы не пришел дубликат уже полученной(или не появилось дырки в случае удаления).

Фильтры поиска и сортировка

  • Поиск осуществляется экшеном index.
  • Зачастую в коллекциях в которых нужна сортировка, она просто встроена. И не нужно никаких параметров.
  • Фильтры поиска задаются через query-параметры
  • Параметры сортировки тоже задается через query-параметры. Рекомендуется query-параметр sort, если нужна сортировка в обратном порядке - то перед именем поля задается знак минус.

Пример: /users/4/articles?sort=-name&title=домашние+животные

  • Сортировка по name в обратном порядке
  • Фильтр статей по автору. ID пользователя равно 4
  • Фильтр по названию. Название должно содержать слова 'домашние животные'

Система Аутентификации

Термины:

  • Аутентификация - Процесс получения token'a на основе логина и пароля. Другими словами проверка подлинности источника запроса.
  • Авторизация - наделение пользователя правами на выполнение определенных действий. Другими словами - предоставление доступа к чему, для пользователя, который предварительно аутентифицирован
  • Идентификация - Опознавание пользователя на основе token'a

В случае неудачи вернется статус:

  • 401 - не аутентифицирован
  • 403 - не авторизирован(идентифицирован, но не доступа к этому запросу)

Протокол идентификации: HTTP Bearer token

В кратце: нужно отправить заголовок формата Authorization: Bearer <token>

Где

  • Bearer - обязательное слово указывающее способ идентификации.
  • <token> - уникальный идентификатор пользователя. Пример token'a: FFFF70it7tzNsHddEiq0BZ0i-OU8S3xV

Локализация

Язык ответа задается заголовком: Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4

Можно просто: Accept-Language: ru

Общие коды ответов:

200: OK. Everything worked as expected.
201: A resource was successfully created in response to a POST request. The Location header contains the URL pointing to the newly created resource.
207: Multistatus
204: The request was handled successfully and the response contains no body content (like a DELETE request).
304: The resource was not modified. You can use the cached version.
400: Bad request. This could be caused by various actions by the user, such as providing invalid JSON data in the request body, providing invalid action parameters, etc.
401: Authentication failed.
403: The authenticated user is not allowed to access the specified API endpoint.
404: The requested resource does not exist.
405: Method not allowed. Please check the Allow header for the allowed HTTP methods.
413: Request Entity Too Large
415: Unsupported media type. The requested content type or version number is invalid.
422: Data validation failed (in response to a POST request, for example). Please check the response body for detailed error messages.
429: Too many requests. The request was rejected due to rate limiting.
500: Internal server error. This could be caused by internal program errors.

Ошибки валидации

  • Ошибки валидации имеют статус 422
  • Для одного поля всегда вернется только одна ошибка

Формат ответа при ошибках валидации такой:

[
  {
    "field": "Название поля в котором ошибка",
    "message": "Локализованный текст ошибки"
  },
  {
    ... другая ошибка ...
  }
]

По вопросам и предложениям обращаться в issuse