================
 Устройство API
================

HTTP заголовки запроса
======================

Каждый запрос может быть сопровожден следующими заголовками:

* **Accept** - формат данных. Например ``Accept: application/json``
* **Authorization** - авторизационный токен. ``Authorization: OAuth {token}``
* **X-UID** - uid пользователя (смотри раздел :ref:`internal-clients`)
* **X-USER-IP** - ipv4/ipv6 исходного клиента (смотри раздел :ref:`internal-clients`)
* **X-Request-ID** - идентификатор запроса. Не более 60 символов. Валидация по регулярному выражению ``^[\w\d-]+$``
* **X-Debug** - включение логирования отладочной информации: времени работы определенных участков кода, используемых соединений к базе и т.п.

HTTP заголовки ответа
=====================

Нужно отметить некоторые заголовки ответа:

* **Content-Type** - всегда ``application/json; charset=utf-8``
* **WWW-Authenticate** - в случае проблем с авторизацией предоставляет информацию о ошибке для клиентов.
  Например ``WWW-Authenticate: OAuth error='expired_token'``
* **Link** - заголовок с информацией для `пагинации <http://tools.ietf.org/html/rfc5988>`_. Удобно использовать в продвинутых
  клиентах (например, `python-requests <http://docs.python-requests.org/en/latest/user/advanced/#link-headers>`_)
* **X-Revision** - номер ревизии организации.  Сейчас поббержано только в get users
* **X-Request-ID** - идентификатор запроса. Если не передан в момент выполнения запроса,
  то вернется рандомно сгенерированная строка

Версионирование
===============

Нужную версию API можно запросить с помощью указания префикса версии в пути, например: ``/v2/users/``.
В данный момент по умолчанию отдаётся первая версия ручек (``v1``), но в будущем указание номера версии будет требоваться в обязательном порядке.


Формат полей
============

Даты представлены по стандарту `iso-8601`_ в ``UTC``.

Каждая сущность (пользователь, группа, ресурс...) имеет поле ``id``, которое уникально в рамках сущностей этого типа. То есть, возможно существование отдела с ``id=1`` и команды с ``id=1``.

Локализованные поля
===================

.. warning:: Будет отменено к публичной версии API.

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

    {
        "en": "Content-Services Maintenance Service",
        "ru": "Служба эксплуатации контент-сервисов"
    }


Дата и время
============

``Datetime`` поля представлены по стандарту `iso-8601`_ с точностью до микросекунд, и могут включать в себя смещение относительно ``UTC``. Пример::

    {
        "created_at": "2016-11-02T16:33:27.482518+03:00",
    }

Пример даты без времени::

    {
        "birthday": "1990-03-02"
    }


Пейджинация по результатам
==========================

Пример ответа по запросу пользователей ``/users/``::

    {
        "links": {
            "next": "https://dir.yandex.ru/users/page=4&per_page=10",
            "prev": "https://dir.yandex.ru/users/page=2&per_page=10",
            "last": "https://dir.yandex.ru/users/page=10&per_page=10",
            "first": "https://dir.yandex.ru/users/page=1&per_page=10"
        }
        "page": 3,
        "per_page": 10,
        "pages": 10,
        "total": 100,
        "result": [
            {
                "department": {
                    "id": 1087,
                    "name": "Служба IT инфраструктуры датацентров"
                },
                "email": null,
                "name": {
                    "first": {
                        "en": "Gennady",
                        "ru": "Геннадий"
                    },
                    "last": {
                        "en": "Chibisov",
                        "ru": "Чибисов"
                    }
                },
                "gender": "male",
                "groups": [],
                "id": 110947743,
                "nickname": "nogoodi4"
            },
            ...
        ]
    }

* **links** - объект с информацией о пагинации:
* **page** - текущая страница
* **per_page** - какое кол-во объектов выведено на странице
* **pages** - общее кол-во страниц
* **total** - общее кол-во сущностей
* **result** - список сущностей

Пейджинация осуществляется за счёт словаря ``links``, в котором могут присутствовать ссылки на
следующую и предыдущую страницы, а так же на самую первую и самую последнюю страницы.
Эти же ссылки доступны и в HTTP заголовке ``Links``, а некоторые http библиотеки, например
`python-requests <http://docs.python-requests.org/en/latest/user/advanced/#link-headers>`_,
умеют работать с этим заголовком.

Выборка вложенных объектов
==========================

.. warning:: В публичной версии API вложенные объекты не будут раскрываться по умолчанию
             и надо будет явно указать, что нужно раскрыть какое-то поле.

Все вложенные объекты должны по возможности раскрываться. Например, у пользователя есть список групп. Они будут
выведены раскрытым списком объектов::

    {
        ...
        "email": "web-chib@ya.ru",
        "groups": [
            {
                "id": 30141,
                "name": {
                    "en": "Males",
                    "ru": "Мужчины"
                }
            },
            ...
        ]
        ...
    }

В случае, если вложенный объект сам по себе содержит вложенный объект, то его не нужно раскрывать. Например, у
пользователя есть департамент. Его нужно раскрыть. Но у самого департамента есть родительский департамент. Его нужно
показать как идентификатор::

    {
        ...
        "email": "web-chib@ya.ru",
        "department": {  // объект департамента раскрыт
            "id": 181,
            "name": {
                "en": "Group of entertainment services development",
                "ru": "Группа разработки развлекательных сервисов"
            },
            "parent_id": 100  // объект следующей вложенности не раскрыт
        },
        ...
    }

В случае указания идентификатора объекта название атрибута должно оканчиваться на ``_id``. Например ``parent_id``.

Установка вложенных объектов
============================

Установка связей с одних объектов с другими должна осуществляться через указание их идентификаторов.
Например так, можно при создании пользователя указать id отдела, в котором он должен состоять::

    POST /users/

    {
        ...
        "email": "web-chib@ya.ru",
        "department_id": 181
        ...
    }

Атрибут, содержащий идентификатор вложенного объекта, должен заканчиваться на ``_id``.
Если вложенный объект представляет из себя список объектов, то атрибут должен заканчиваться на ``_ids``::

    PUT /users/

    {
        ...
        "email": "web-chib@ya.ru",
        "group_ids": [1,2,3]
        ...
    }

Фильтры
=======

Фильтры списка сущностей должны осуществляться указанием ``GET`` параметров. В случае фильтрации по вложенным объектам
название этих параметров должно оканчиваться на ``_id``::

    /users/?department_id=1

Некоторые ресурсы поддерживают фильтрацию сразу по нескольким значениям одного атрибута. Для этого необходимо
перечислить значения через запятую, не изменяя названия параметра. Отношение в выборке между каждым значением ``OR``.
Ниже представлен пример выборки "вывести пользователей с департаментом 1 ИЛИ 2"::

    /users/?department_id=1,2

В случае указания нескольких фильтрующих параметров отношение между ними ``AND``.
Ниже представлен пример выборки "вывести пользователей с (департаментом 1 ИЛИ 2) И (идентификатором 2 или 3)"::

    /users/?department_id=1,2&id=2,3

Сортировка
==========

При запросе списка сущностей можно указать порядок сортировки с помощью GET-параметра ``ordering``::

    /departments/?ordering=name

Список полей, по которым можно сортировать данные можно узнать в описании конкретной ручки. Для обратной сортировки нужно указать название поля со знаком ``-``, например::

    /departments/?ordering=-id

Можно указать список полей для сортировки через запятую::

    /departments/?ordering=name,id

Если будет указано неподдерживаемое имя поля для сортировки, API вернет ошибку с кодом 422.

Ошибки
======

В случае ошибок ручки возращают ответ с HTTP кодом >= 400.
В теле ответа содержится более подробная информация об ошибках::

    {
      "code": "some_error_happened",
      "message": "Something happened with {obj} object",
      "params": {
        "obj": "The User",
      }
    }

  При этом, params может отсутствовать, если ``message`` не содержит
  плейсхолдеров, типа ``{obj}``.

  Возможные коды ошибок, и их расшифровки описаны в разделе `Ошибки API`_.


.. _iso-8601: http://ru.wikipedia.org/wiki/ISO_8601
