Проект

Общее

Профиль

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

Александр Кварацхелия, 07.04.2014 19:06

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