Проект

Общее

Профиль

Действия

API

Общие сведения об API Неба

Сервер Неба поддерживает взаимодействие с внешними приложениями с использованием REST-подобного API. По сути, это же API используется для работы клиентского (браузерного) приложения Неба, что позволяет внешним приложениям реализовать все те же действия, что и пользователь в основном интерфейсе Неба.

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

Текущая версия API пока не является фиксированной. Возможны изменения в составе передаваемых данных без предварительного уведомления взаимодействующих внешних приложений. Фиксация API по разделам Неба и последующая его версионность будут реализованы позже.

Также помните, что на текущий момент времени "защита от дурака" в Небе равномерно распределена между клиентским и серверным приложением. Значительная часть ограничений на использование Неба (в основном, некритичных для безопасности и целостности данных) реализованы путем выбора специфической схемы организации клиентского приложения, без их дублирования на серверной части. Поэтому, перед использованием тех или иных операций желательно убедиться, что они не противоречат логике предметной области и текущего поведения Неба в целом (например, посмотрев как требуемая операция реализована в интерфейсе Неба).

API по разделам Неба

API - Организации
API - Учетная политика
API - Контрагенты
API - Номенклатура
API - Счета на оплату
API - Денежные средства

Аутентификация внешнего приложения

Для аутентификации пользователей применяется общепринятая для Web-приложений схема.

1. Внешнее приложение отсылает GET или POST запрос на URL https://nebopro.ru/loging передавая в параметрах запроса следующие значения:
  • login - email зарегистрированного в Небе пользователя;
  • pass - его пароль

2. В ответе сервера будет находится JSON объект с {"success": true} при успешной аутентификации, либо {"success": false, "msg": "Текст с причиной, почему не удалось аутентифицировать пользователя"}.

3. В заголовке ответа сервер проставляет cookie с именем sessionid, которое является сессионным ключом данного пользователя. Здесь же сервер указывает максимальный срок жизни сессии - параметр expires.

Полученный sessionid необходимо указывать в cookie всех последующих HTTP-запросов к серверу.

Пример аутентификации с последующим получением списка пользователей в аккаунте

Пример приведен на языке python

#coding:utf-8

import urllib, urllib2  # библиотека python, которая позволяет работать с HTTP запросами
import json

def authenticate(username, password):
    u""" 
    Аутентифицирует пользователя в Небе, возвращая строку с sessionid. При неудачной попытке 
    возвращается None
    """ 

    # формируем параметры запроса и энкодим их, чтобы они нормально ушли как параметры GET запроса
    params = urllib.urlencode({
        'login': username,
        'pass': password
    })

    # объект запроса
    req = urllib2.Request('https://nebopro.ru/loging', params)

    # получаем ответ
    resp = urllib2.urlopen(req)

    # читаем содержимое ответа
    data = json.loads(resp.read())  

    result = None
    if data['success']:
        # чтобы не уклоняться от темы, выделим sessionid таким решительным способом
        result = unicode(resp.headers['Set-Cookie'], 'utf-8')[10:42]

    return result

def get_users(sessionid):
    u""" Возвращает JSON объект со списком пользователей """ 

    req = urllib2.Request('https://nebopro.ru/core/nebo-user/list')
    req.add_header('Cookie', "sessionid=" + sessionid + ';')
    resp = urllib2.urlopen(req)

    result = None
    if resp.getcode() == 200 and resp.info().type == 'application/json':
        # В некоторых случаях, в т.ч. при выполнении запроса с невалидным sessionid сервер вернет
        # ответ с типом содержимого text/html. Поэтому, при анализе ответа необходимо проверять
        # HTTP-статус ответа 200 и тип ответа application/json
        result = json.loads(resp.read())['data']
    return result

# получаем ключ доступа
sessionid = authenticate('akvarats@nebopro.ru', '*******')
# получаем список пользователей
users =  get_users(sessionid)

Для аккаунта с одним пользователем в users будет следующий список из одного объекта

[{
    "profile": {
        "status": {
            "name": "\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442",
            "id": 3
        },
        "first_name": "akvarats@nebopro.ru",
        "last_name": "",
        "middle_name": "",
        "uid": "*******************",
        "is_active": true,
        "id": 638,
        "phone": "8 927 400 12 05",
        "is_admin": true,
        "full_name": "akvarats@nebopro.ru",
        "phone_binding": {
            "can_bind_phone": false,
            "phone_bound": false
        },
        "auth_user": {
            "id": 647
        },
        "email": "akvarats@nebopro.ru" 
    },
    "cnt": {
        "itsme": true,
        "hd": false
    },
    "permissions": [{
        "chapter": null,
        "access_level": {
            "name": "\u041f\u043e\u043b\u043d\u044b\u0439",
            "id": 1
        },
        "company": {
            "name": "akvarats@nebopro.ru",
            "profiles": [],
            "id": 668
        }
    }, {
        "chapter": null,
        "access_level": {
            "name": "\u041f\u043e\u043b\u043d\u044b\u0439",
            "id": 1
        },
        "company": {
            "name": "\u041a\u043e\u043c\u043f\u0430\u043d\u0438\u044f \u0438\u0437 47 \u0440\u0435\u0433\u0438\u043e\u043d\u0430",
            "profiles": [],
            "id": 9148
        }
    }, {
        "chapter": null,
        "access_level": {
            "name": "\u041f\u043e\u043b\u043d\u044b\u0439",
            "id": 1
        },
        "company": {
            "name": "\u041a\u043e\u043c\u043f\u0430\u043d\u0438\u044f \u0438\u0437 78 \u0440\u0435\u0433\u0438\u043e\u043d\u0430",
            "profiles": [],
            "id": 9149
        }
    }],
    "user": {
        "uid": "7951d057-a19f-47d8-afdd-63d66fe85b8e",
        "user_fio": "akvarats@nebopro.ru",
        "email": "akvarats@nebopro.ru",
        "id": 728
    },
    "phone_binding": {
        "can_bind_phone": false,
        "phone_bound": false
    }
}]

Рабочая организация

В случае если в аккаунте пользователя создано более одной организации, то перед выполнением манипуляций с данными необходимо явно указывать, какая из организаций является рабочей. Сервер сохраняет текущую рабочую организацию либо до следующей операции её смены, либо до завершения серверной сессии. По умолчанию, рабочей является первая созданная организация в аккаунте (с наименьшим id).

Для получения списка организаций в аккаунте используется запрос без параметров по URL https://nebopro.ru/nebo/user-env/company_list. В ответ на данный запрос приходит информация о полном окружении текущего пользователя, в том числе и список организаций, к которым пользователь имеет доступ:

Для установки текущей рабочей организации необходимо отправить запрос по URL https://nebopro.ru/nebo/user-env/set_company, указав в параметре company_id идентификатор (id) той компании, которую необходимо сделать текущей. GET-версия такого запроса будет выглядеть так https://nebopro.ru/nebo/user-env/set_company?company_id=668 (подробнее о GET- и POST- версиях запросов см. ниже в разделе с описание REST-операций). В ответ на такой запрос приходит json объект вида {"data": {"name": "akvarats@nebopro.ru", "id": 668}, "success": true}.

Особенности выполнения REST-операций

Для большинства серверных ресурсов (если рассматривать сервер Неба именно как REST-сервер) заданы следующие операции:

  • list получение списка экземпляров ресурса;
  • read получение единственного экземпляра ресурса по идентификатору (первичному ключу);
  • create - создание нового экземпляра;
  • update - изменение существующего экземпляра;
  • delete - удаление экземпляра.

Особенностью Неба является то, что требуемая от сервера операция над ресурсом задается не типом запроса (GET, POST, PUT, DELETE), а последней частью соответствующего ресурсу URL'а. Например, при работе с контрагентами мы имеем следующие URL'ы:

  • /core/contragents/list
  • /core/contragents/read
  • /core/contragents/create
  • /core/contragents/update
  • /core/contragents/delete

Тип запроса (GET или POST) в подавляющем большинстве случаев влияет только на способ и вид передачи параметров: в заголовках (как в GET) или в теле (как в POST). Ниже показано, как одна и та же операция может быть выполнена обоими способами.

Операция LIST

Принимает параметры:
  • offset (целое, необязательное) - параметр для постраничного вывода результата - смещение курсора в выборке;
  • limit (целое, необязательное) - параметр для постраничного вывода результата - количество записей в результате;
  • filter (json-объект, необязательно) - задает условие фильтрации (формат описания см. ниже);
  • order (json-объект, необязательно) - задает условие сортировки результирующего списка (формат описания см.ниже).

Возвращает JSON объект вида

{
    "success": true,
    "data": [{}, {}, {}],
    "total": 100500
}

Здесь:
  • success (true/false) указывает на успешность выполнения операции
  • data - результирующий список объектов
  • total - общее количество записей (используется при постраничном чтении данных)

Фильтр на записи задается в виде JSON объекта с деревом выражений-условий

{
    "left": left_subexpression,
    "op": operator,
    "right": right_subexpression
}

В качестве left_subexpression могут выступать либо вложенные подвыражения-условия, либо имя поля, на которое накладывается условие. В right_subexpression - либо подвыражения условия, либо значение, с которым сравнивается значение в поле. В случае, если слева-справа указаны подвыражения, то в operator указывается логическое условие. Иначе, указывается оператор сравнения.

В условиях фильтра допустимо задавать следующие виды операторов:

  • and - логическое И. В left и right ожидаются вложенные объекты с условиями;
  • or' - логическое ИЛИ. В left и right ожидаются вложенные объекты с условиями;
  • not - логическое НЕ. В left ожидается условие, на которое накладывается отрицание. В right ожидается null;
  • eq - значение в поле с именем из left должно быть равно значению из right;
  • neq - значение в поле с именем из left должно быть не равно значению из right;
  • lt - значение в поле с именем из left должно быть меньше значения из right;
  • lte - значение в поле с именем из left должно быть меньше или равно значения из right;
  • gt - значение в поле с именем из left должно быть больше значения из right;
  • gte - значение в поле с именем из left должно быть больше или равно значения из right;
  • icontains - значение в поле с именем из left должно регистро-независимо содержать значения из right (используется для сравнения строк);
  • iexact - значение в поле с именем из left должно регистро-независимо совпадать со значения из right (используется для сравнения строк);
  • in - значение в поле с именем из left должно содержаться в списке значений из right;
  • startswith - значение в поле с именем из left должно начинаться значением из right (используется для сравнения строк);
  • istartswith - значение в поле с именем из left должно регистро-независимо начинаться значением из right (используется для сравнения строк);
  • endswith - значение в поле с именем из left должно заканчиваться значением из right (используется для сравнения строк);
  • iendswith - значение в поле с именем из left должно регистро-независимо заканчиваться значением из right (используется для сравнения строк);
  • fts - оператор псевдо-полнотекстового поиска. Выполняет регистро-независимый поиск по вхождению строки из right по совокупности полей, которые определены для серверного ресурса. Значение в left при этом игнорируется.

Пример запроса для нахождения контрагента, ИНН которого равен "0000000000":

В случае, если необходимо найти контрагента по двум условиям (например, ИНН равен 0000000000 и КПП равен 000000000), то объект фильтра выглядит следующим образом:

{
    "left": {"left": "inn", "op": "eq", "right": "0000000000"},
    "op": "and",
    "right": {"left": "kpp", "op": "eq", "right": "000000000"}
}

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

{ 
    "type": "array-and",
    "data": [{"left": "inn", "op": "eq", "right": "0000000000"}, {"left": "kpp", "op": "eq", "right": "000000000"}]
}

Здесь type: "array-and" указывает на то, что объекты с условиями из data должны соединиться условием AND. Аналогично, для записывания каскада условий, соединенных OR, используется type: "array-or".

При выполнении операции LIST в виде GET запроса, используются те же параметры, и URL при правильном энкодинге параметров будет выглядеть примерно так: https://nebopro.ru/core/contract/list?offset=0&limit=20&filter=%7B"type"%3A"array-and"%2C"data"%3A%5B%7B"left"%3A"contragent_id"%2C"op"%3A"eq"%2C"right"%3A"20445"%7D%5D%7D&order=""

Условие сортировки задается следующим:

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

Операция READ

Возвращает данные одного экземпляра ресурса по первичному ключу. Имя поля с первичным ключом (обычно, id) и значение первичного ключа передаются в параметрах запроса в виде пары "ключ-значение".

Например, чтобы прочитать данные договора с идентификатором 19491 необходимо отправить GET-запрос https://nebopro.ru/core/contract/read?id=19491 или его POST-аналог как указано на рисунке:

В отдельных случаях, первичного идентификатора не достаточно для чтения объекта с сервера. Чтобы уточнить состав данных для операции READ необходимо воспользоваться средствами разработчика Вашего браузера:

Для операции READ есть одна особенность. Если первичный идентификатор (id) не указан, то сервер возвращает новый (ещё не сохраненный в БД) экземпляр ресурса с проставленными в полях значениями по умолчанию. По виду такого нового объекта можно судить о наборе полей, которые заданы для данного типа ресурса.

Операция CREATE

Принимает те параметры, которые необходимо записать для нового экземпляра данного ресурса. Параметры указываются в виде JSON объекта в теле POST запроса или параметрами в URL для GET запроса. Форма с POST запросом предпочтительнее, поскольку размер заголовка запроса обычно ограничен.

Возвращает {"success":true} (в некоторых случаях, {"success":true, "data": {"id": 1234}}) при успешном выполнении операции.

Операция UPDATE

Операция UPDATE аналогична CREATE с тем различием, что в параметрах должен быть обязательно указан первичный ключ объекта (id), данные которого необходимо изменить. Возвращает {"success":true} при успешном выполнении операции.

Операция DELETE

DELETE принимает в качестве параметра обязательное значение первичного ключа объекта (id), который необходимо удалить. Возвращает {"success":true} при успешном выполнении операции.

При выполнении операции DELETE используется каскадный принцип (все записи, на которые ссылается удаленный объект так же удаляются). Чтобы узнать, если ли ссылки на объект необходимо использовать операцию CHECK_REFS, которая принимает на входе список список идентификаторов объектов (параметр ids) и возвращает список ссылок на объекты, заданные в списке идентификаторов ids:

Прочие операции

Поскольку API Неба обеспечивает REST-подобный интерфейс системы, существует некоторое количество прочих операций (отличный от общепринятых CRUD-операций), которые можно выполнять над серверными ресурсами. Для каждого такого случая необходимо уточнять входные и выходные параметры в консоли разработчика Вашего браузера.

Обновлено Артем Туровец больше 8 лет назад · 30 изменени(я, ий)