Проект

Общее

Профиль

API » История » Версия 26

Александр Кварацхелия, 06.11.2014 11:43

1 1 Александр Кварацхелия
h1. API
2
3 12 Александр Кварацхелия
{{toc}}
4
5 1 Александр Кварацхелия
h2. Общие сведения об API Неба
6
7
Сервер Неба поддерживает взаимодействие с внешними приложениями с использованием REST-подобного API. По сути, это же API используется для работы клиентского (браузерного) приложения Неба, что позволяет внешним приложениям реализовать все те же действия, что и пользователь в основном интерфейсе Неба.
8
9
При использовании текущей версии API Неба необходимо осознавать, что оно предназначено в первую очередь для функционирования основного клиентского приложения Неба. Все спорные и неоднозначные моменты в данном API возникли из-за того, что в первую очередь максимизировалось удобства разработки и функционирования именно клиентского приложения. 
10
11
Текущая версия API пока не является фиксированной. Возможны изменения в составе передаваемых данных без предварительного уведомления взаимодействующих внешних приложений. Фиксация API по разделам Неба и последующая его версионность будут реализованы в течение 2014 года.
12
13
Также помните, что на текущий момент времени "защита от дурака" в Небе равномерно распределена между клиентским и серверным приложением. Значительная часть ограничений на использование Неба (в основном, некритичных для безопасности и целостности данных) реализованы путем выбора специфической схемы организации клиентского приложения, без их дублирования на серверной части. Поэтому, перед использованием тех или иных операций желательно убедиться, что они не противоречат логике предметной области и текущего поведения Неба в целом (например, посмотрев как требуемая операция реализована в интерфейсе Неба).
14
15 19 Александр Кварацхелия
h2. API по разделам Неба
16
17
[[API - Организации]]
18 26 Александр Кварацхелия
[[API - Учетная политика]]
19 19 Александр Кварацхелия
[[API - Контрагенты]]
20
[[API - Номенклатура]]
21
[[API - Счета на оплату]]
22 26 Александр Кварацхелия
[[API - Денежные документы]]
23
[[API - Платежные поручения]]
24 20 Александр Кварацхелия
25 1 Александр Кварацхелия
h2. Аутентификация внешнего приложения
26
27
Для аутентификации пользователей применяется общепринятая для Web-приложений схема.
28
29
1. Внешнее приложение отсылает GET или POST запрос на URL @https://nebopro.ru/loging@ передавая в параметрах запроса следующие значения:
30
* @login@ - email зарегистрированного в Небе пользователя;
31
* @pass@ - его пароль
32
33
2. В ответе сервера будет находится JSON объект с @{"success": true}@ при успешной аутентификации, либо @{"success": false, "msg": "Текст с причиной, почему не удалось аутентифицировать пользователя"}@.
34
35 3 Александр Кварацхелия
3. В заголовке ответа сервер проставляет cookie с именем @sessionid@, которое является сессионным ключом данного пользователя. Здесь же сервер указывает максимальный срок жизни сессии - параметр @expires@. 
36 1 Александр Кварацхелия
37
!loging-sessionid.png!
38 3 Александр Кварацхелия
39
Полученный @sessionid@ необходимо указывать в cookie всех последующих HTTP-запросов к серверу.
40 4 Александр Кварацхелия
41
h2. Пример аутентификации с последующим получением списка пользователей в аккаунте
42
43
Пример приведен на языке python
44
45
<pre>
46
<code class="python">
47
#coding:utf-8
48
49
import urllib, urllib2  # библиотека python, которая позволяет работать с HTTP запросами
50
import json
51
52
def authenticate(username, password):
53
    u""" 
54
    Аутентифицирует пользователя в Небе, возвращая строку с sessionid. При неудачной попытке 
55
    возвращается None
56
    """
57
58
    # формируем параметры запроса и энкодим их, чтобы они нормально ушли как параметры GET запроса
59
    params = urllib.urlencode({
60
        'login': username,
61
        'pass': password
62
    })
63
64
    # объект запроса
65
    req = urllib2.Request('https://nebopro.ru/loging', params)
66
67
    # получаем ответ
68
    resp = urllib2.urlopen(req)
69
70
    # читаем содержимое ответа
71
    data = json.loads(resp.read())  
72
73
    result = None
74
    if data['success']:
75
        # чтобы не уклоняться от темы, выделим sessionid таким решительным способом
76
        result = unicode(resp.headers['Set-Cookie'], 'utf-8')[10:42]
77
78
    return result
79
80
81
def get_users(sessionid):
82
    u""" Возвращает JSON объект со списком пользователей """
83
84
    req = urllib2.Request('https://nebopro.ru/core/nebo-user/list')
85
    req.add_header('Cookie', "sessionid=" + sessionid + ';')
86
    resp = urllib2.urlopen(req)
87
88
    result = None
89
    if resp.getcode() == 200 and resp.info().type == 'application/json':
90
        # В некоторых случаях, в т.ч. при выполнении запроса с невалидным sessionid сервер вернет
91
        # ответ с типом содержимого text/html. Поэтому, при анализе ответа необходимо проверять
92
        # HTTP-статус ответа 200 и тип ответа application/json
93
        result = json.loads(resp.read())['data']
94
    return result
95
96
# получаем ключ доступа
97
sessionid = authenticate('akvarats@nebopro.ru', '*******')
98
# получаем список пользователей
99
users =  get_users(sessionid)
100
</code>
101
</pre>
102
103
Для аккаунта с одним пользователем в @users@ будет следующий список из одного объекта
104
<pre>
105
<code class="json">
106
[{
107
    "profile": {
108
        "status": {
109
            "name": "\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442",
110
            "id": 3
111
        },
112
        "first_name": "akvarats@nebopro.ru",
113
        "last_name": "",
114
        "middle_name": "",
115
        "uid": "*******************",
116
        "is_active": true,
117
        "id": 638,
118
        "phone": "8 927 400 12 05",
119
        "is_admin": true,
120
        "full_name": "akvarats@nebopro.ru",
121
        "phone_binding": {
122
            "can_bind_phone": false,
123
            "phone_bound": false
124
        },
125
        "auth_user": {
126
            "id": 647
127
        },
128
        "email": "akvarats@nebopro.ru"
129
    },
130
    "cnt": {
131
        "itsme": true,
132
        "hd": false
133
    },
134
    "permissions": [{
135
        "chapter": null,
136
        "access_level": {
137
            "name": "\u041f\u043e\u043b\u043d\u044b\u0439",
138
            "id": 1
139
        },
140
        "company": {
141
            "name": "akvarats@nebopro.ru",
142
            "profiles": [],
143
            "id": 668
144
        }
145
    }, {
146
        "chapter": null,
147
        "access_level": {
148
            "name": "\u041f\u043e\u043b\u043d\u044b\u0439",
149
            "id": 1
150
        },
151
        "company": {
152
            "name": "\u041a\u043e\u043c\u043f\u0430\u043d\u0438\u044f \u0438\u0437 47 \u0440\u0435\u0433\u0438\u043e\u043d\u0430",
153
            "profiles": [],
154
            "id": 9148
155
        }
156
    }, {
157
        "chapter": null,
158
        "access_level": {
159
            "name": "\u041f\u043e\u043b\u043d\u044b\u0439",
160
            "id": 1
161
        },
162
        "company": {
163
            "name": "\u041a\u043e\u043c\u043f\u0430\u043d\u0438\u044f \u0438\u0437 78 \u0440\u0435\u0433\u0438\u043e\u043d\u0430",
164
            "profiles": [],
165
            "id": 9149
166
        }
167
    }],
168
    "user": {
169
        "uid": "7951d057-a19f-47d8-afdd-63d66fe85b8e",
170
        "user_fio": "akvarats@nebopro.ru",
171
        "email": "akvarats@nebopro.ru",
172
        "id": 728
173
    },
174
    "phone_binding": {
175
        "can_bind_phone": false,
176
        "phone_bound": false
177
    }
178
}]
179
</code>
180
</pre>
181 5 Александр Кварацхелия
182 14 Александр Кварацхелия
h2. Рабочая организация
183
184
В случае если в аккаунте пользователя создано более одной организации, то перед выполнением манипуляций с данными необходимо явно указывать, какая из организаций является рабочей. Сервер сохраняет текущую рабочую организацию либо до следующей операции её смены, либо до завершения серверной сессии. По умолчанию, рабочей является первая созданная организация в аккаунте (с наименьшим @id@).
185
186
Для получения списка организаций в аккаунте используется запрос без параметров по URL https://nebopro.ru/nebo/user-env/company_list. В ответ на данный запрос приходит информация о полном окружении текущего пользователя, в том числе и список организаций, к которым пользователь имеет доступ:
187
!user-env1.png!
188
189
Для установки текущей рабочей организации необходимо отправить запрос по 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}@.
190
191 5 Александр Кварацхелия
h2. Особенности выполнения REST-операций
192
193
Для большинства серверных ресурсов (если рассматривать сервер Неба именно как REST-сервер) заданы следующие операции:
194
195
* @list@ получение списка экземпляров ресурса;
196
* @read@ получение единственного экземпляра ресурса по идентификатору (первичному ключу);
197
* @create@ - создание нового экземпляра;
198
* @update@ - изменение существующего экземпляра;
199
* @delete@ - удаление экземпляра.
200
201
Особенностью Неба является то, что требуемая от сервера операция над ресурсом задается не типом запроса (GET, POST, PUT, DELETE), а последней частью соответствующего ресурсу URL'а. Например, при работе с контрагентами мы имеем следующие URL'ы:
202
203
* /core/contragents/list
204
* /core/contragents/read
205
* /core/contragents/create
206
* /core/contragents/update
207
* /core/contragents/delete
208 1 Александр Кварацхелия
209 12 Александр Кварацхелия
Тип запроса (GET или POST) в подавляющем большинстве случаев влияет только на способ и вид передачи параметров: в заголовках (как в GET) или в теле (как в POST). Ниже показано, как одна и та же операция может быть выполнена обоими способами.
210 5 Александр Кварацхелия
211
h3. Операция LIST
212
213
Принимает параметры:
214
* @offset@ (целое, необязательное) - параметр для постраничного вывода результата - смещение курсора в выборке;
215
* @limit@ (целое, необязательное) - параметр для постраничного вывода результата - количество записей в результате;
216
* @filter@ (json-объект, необязательно) - задает условие фильтрации (формат описания см. ниже);
217 8 Александр Кварацхелия
* @order@ (json-объект, необязательно) - задает условие сортировки результирующего списка (формат описания см.ниже).
218 5 Александр Кварацхелия
219
Возвращает JSON объект вида
220
<pre>
221
<code class="json">
222
{
223
    "success": true,
224
    "data": [{}, {}, {}],
225
    "total": 100500
226
}
227
</code>
228
</pre>
229
230
Здесь:
231
* @success@ (true/false) указывает на успешность выполнения операции
232
* @data@ - результирующий список объектов
233
* @total@ - общее количество записей (используется при постраничном чтении данных)
234
235 6 Александр Кварацхелия
Фильтр на записи задается в виде JSON объекта с деревом выражений-условий 
236 1 Александр Кварацхелия
<pre>
237 6 Александр Кварацхелия
<code class="json">
238
{
239
    "left": left_subexpression,
240
    "op": operator,
241
    "right": right_subexpression
242
}
243
</code>
244 5 Александр Кварацхелия
</pre>
245 1 Александр Кварацхелия
246 6 Александр Кварацхелия
В качестве @left_subexpression@ могут выступать либо вложенные подвыражения-условия, либо имя поля, на которое накладывается условие. В @right_subexpression@ - либо подвыражения условия, либо значение, с которым сравнивается значение в поле. В случае, если слева-справа указаны подвыражения, то в @operator@ указывается логическое условие. Иначе, указывается оператор сравнения.
247
248 5 Александр Кварацхелия
В условиях фильтра допустимо задавать следующие виды операторов:
249
250
* @and@ - *логическое И*. В @left@ и @right@ ожидаются вложенные объекты с условиями;
251
* @or@' - *логическое ИЛИ*. В @left@ и @right@ ожидаются вложенные объекты с условиями;
252
* @not@ - *логическое НЕ*. В @left@ ожидается условие, на которое накладывается отрицание. В @right@ ожидается null;
253
* @eq@ - значение в поле с именем из @left@ должно быть *равно* значению из @right@;
254
* @neq@ - значение в поле с именем из @left@ должно быть *не равно* значению из @right@;
255
* @lt@ - значение в поле с именем из @left@ должно быть *меньше* значения из @right@;
256
* @lte@ - значение в поле с именем из @left@ должно быть *меньше или равно* значения из @right@;
257
* @gt@ - значение в поле с именем из @left@ должно быть *больше* значения из @right@;
258
* @gte@ - значение в поле с именем из @left@ должно быть *больше или равно* значения из @right@;
259 8 Александр Кварацхелия
* @icontains@ - значение в поле с именем из @left@ должно *регистро-независимо содержать* значения из @right@ (используется для сравнения строк);
260
* @iexact@ - значение в поле с именем из @left@ должно *регистро-независимо совпадать* со значения из @right@ (используется для сравнения строк);
261 5 Александр Кварацхелия
* @in@ - значение в поле с именем из @left@ должно *содержаться* в списке значений из @right@;
262
* @startswith@ - значение в поле с именем из @left@ должно *начинаться* значением из @right@ (используется для сравнения строк);
263 8 Александр Кварацхелия
* @istartswith@ - значение в поле с именем из @left@ должно *регистро-независимо начинаться* значением из @right@ (используется для сравнения строк);
264 1 Александр Кварацхелия
* @endswith@ - значение в поле с именем из @left@ должно *заканчиваться* значением из @right@ (используется для сравнения строк);
265 8 Александр Кварацхелия
* @iendswith@ - значение в поле с именем из @left@ должно *регистро-независимо заканчиваться* значением из @right@ (используется для сравнения строк);
266 7 Александр Кварацхелия
* @fts@ - оператор псевдо-полнотекстового поиска. Выполняет регистро-независимый поиск по вхождению строки из @right@ по совокупности полей, которые определены для серверного ресурса. Значение в @left@ при этом игнорируется.
267 6 Александр Кварацхелия
268
Пример запроса для нахождения контрагента, ИНН которого равен "0000000000":
269
270 1 Александр Кварацхелия
!filter-example1.png!
271 7 Александр Кварацхелия
272
В случае, если необходимо найти контрагента по двум условиям (например, ИНН равен 0000000000 и КПП равен 000000000), то объект фильтра выглядит следующим образом:
273
<pre>
274 8 Александр Кварацхелия
<code class="json">
275 7 Александр Кварацхелия
{
276
    "left": {"left": "inn", "op": "eq", "right": "0000000000"},
277
    "op": "and",
278
    "right": {"left": "kpp", "op": "eq", "right": "000000000"}
279
}
280
</code>
281
</pre>
282
283
Комплексные условия фильтров можно задавать с помощью следующих сокращенных записей:
284
<pre>
285
<code class="json">
286
{ 
287
    "type": "array-and",
288 1 Александр Кварацхелия
    "data": [{"left": "inn", "op": "eq", "right": "0000000000"}, {"left": "kpp", "op": "eq", "right": "000000000"}]
289
}
290
</code>
291
</pre>
292
293
Здесь @type: "array-and"@ указывает на то, что объекты с условиями из @data@ должны соединиться условием AND. Аналогично, для записывания каскада условий, соединенных OR, используется @type: "array-or"@.
294
295 12 Александр Кварацхелия
При выполнении операции 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=""
296
297
Условие сортировки задается следующим:
298 8 Александр Кварацхелия
!order-example1.png!
299
300
Пример сортировки результирующего списка по убыванию:
301 9 Александр Кварацхелия
!order-example2.png!
302 10 Александр Кварацхелия
303
h3. Операция READ
304
305
Возвращает данные одного экземпляра ресурса по первичному ключу. Имя поля с первичным ключом (обычно, id) и значение первичного ключа передаются в параметрах запроса в виде пары "ключ-значение".
306
307
Например, чтобы прочитать данные договора с идентификатором 19491 необходимо отправить GET-запрос https://nebopro.ru/core/contract/read?id=19491 или его POST-аналог как указано на рисунке:
308
309 11 Александр Кварацхелия
!read-example1.png!
310 10 Александр Кварацхелия
311
В отдельных случаях, первичного идентификатора не достаточно для чтения объекта с сервера. Чтобы уточнить состав данных для операции READ необходимо воспользоваться средствами разработчика Вашего браузера:
312
!read-example2.png!
313
314 1 Александр Кварацхелия
Для операции READ есть одна особенность. Если первичный идентификатор (@id@) не указан, то сервер возвращает *новый* (ещё не сохраненный в БД) экземпляр ресурса с проставленными в полях значениями по умолчанию. По виду такого нового объекта можно судить о наборе полей, которые заданы для данного типа ресурса.
315
316 12 Александр Кварацхелия
h3. Операция CREATE
317
318
Принимает те параметры, которые необходимо записать для нового экземпляра данного ресурса. Параметры указываются в виде JSON объекта в теле POST запроса или параметрами в URL для GET запроса. Форма с POST запросом предпочтительнее, поскольку размер заголовка запроса обычно ограничен.
319
320 21 Александр Кварацхелия
Возвращает <code class="json">{"success":true}</code> (в некоторых случаях, <code class="json">{"success":true, "data": {"id": 1234}}</code>) при успешном выполнении операции.
321 14 Александр Кварацхелия
322 12 Александр Кварацхелия
h3. Операция UPDATE 
323 1 Александр Кварацхелия
324 22 Александр Кварацхелия
Операция UPDATE аналогична CREATE с тем различием, что в параметрах должен быть обязательно указан первичный ключ объекта (@id@), данные которого необходимо изменить. Возвращает <code class="json">{"success":true}</code> при успешном выполнении операции.
325 12 Александр Кварацхелия
326 1 Александр Кварацхелия
h3. Операция DELETE 
327 12 Александр Кварацхелия
328 23 Александр Кварацхелия
DELETE принимает в качестве параметра обязательное значение первичного ключа объекта (@id@), который необходимо удалить. Возвращает <code class="json">{"success":true}</code> при успешном выполнении операции.
329 12 Александр Кварацхелия
330
При выполнении операции DELETE используется каскадный принцип (все записи, на которые ссылается удаленный объект так же удаляются). Чтобы узнать, если ли ссылки на объект необходимо использовать операцию CHECK_REFS, которая принимает на входе список список идентификаторов объектов (параметр @ids@) и возвращает список ссылок на объекты, заданные в списке идентификаторов @ids@:
331 15 Александр Кварацхелия
332
!delete-example1.png!
333 18 Александр Кварацхелия
334 17 Александр Кварацхелия
h3. Прочие операции
335
336
Поскольку API Неба обеспечивает REST-подобный интерфейс системы, существует некоторое количество прочих операций (отличный от общепринятых CRUD-операций), которые можно выполнять над серверными ресурсами. Для каждого такого случая необходимо уточнять входные и выходные параметры в консоли разработчика Вашего браузера.