How-to: Взаимодействие через HTTP-протокол
Пример 1
Условие
Задан некоторый набор городов, привязанных к странам.
CLASS Country 'Страна';
id 'Код' = DATA STRING[20] (Country) IN id;
name 'Имя' = DATA ISTRING[100] (Country) IN id;
country (STRING[20] id) = GROUP AGGR Country c BY id(c);
CLASS City 'Город';
name 'Имя' = DATA ISTRING[100] (City) IN id;
country 'Страна' = DATA Country (City);
nameCountry 'Страна' (City c) = name(country(c));
FORM cities 'Города'
OBJECTS c = City
PROPERTIES(c) name, nameCountry, NEW, DELETE
;
NAVIGATOR {
NEW cities;
}
Нужно отправить на определенный url HTTP-запрос на добавление города в формате JSON.
Решение
postCity 'Отправить' (City c) {
EXPORT JSON FROM countryId = id(country(c)), name = name(c);
LOCAL result = FILE();
EXTERNAL HTTP 'http://localhost:7651/exec?action=Location.createCity' PARAMS exportFile() TO result;
LOCAL code = STRING[10]();
LOCAL message = STRING[100]();
IMPORT JSON FROM result() TO() code, message;
IF NOT code() == '0' THEN {
MESSAGE 'Ошибка: ' + message();
}
}
EXTEND FORM cities
PROPERTIES(c) postCity
;
Оператор EXPORT
создаст JSON в формате FILE
и сохранит его в свойство exportFile
. Пример сформированного файла:
{"countryId":"123","name":"San Francisco"}
Дальше вызывается оп ератор EXTERNAL
, который делает запрос на предопределенный url, передавая туда в качестве Body содержимое сформированного файла. В данном случае, так как свойство в блоке FROM
имеет тип JSON, то в качестве типа контента будет использоваться application/json. В url'е закодированы <пространство имен>.<имя свойства>
. В данном случае пространство именем модуля вызываемого свойства createCity
является Location
. Все параметры передаются по порядку с идентификатором p
. Ответ, который будет получен от сервера, будет записан в свойство result
. Предположим, что ответ получен в формате JSON и имеет один из следующих видов:
{"code":"0","message":"OK"}
{"code":"1","message":"Некорректный код страны"}
Ответ разбирается при помощи оператора IMPORT
, который раскладывает соответствующие параметры в свойства code
и message
соответственно. В случае ошибки пользователю выдается сообщение с текстом ошибки.
Пример 2
Условие
Аналогично Примеру 1.
Нужно принять соответствующий HTTP-запрос и создать новый город в базе данных с параметрами запроса.
Решение
createCity (FILE f) {
LOCAL cy = STRING[20] ();
LOCAL ne = STRING[100] ();
IMPORT JSON FROM f AS FILE TO() cy = countryId, ne = name;
IF NOT country(cy()) THEN {
EXPORT JSON FROM code = '1', message = 'Некорректный код страны';
RETURN;
}
NEW c = City {
name(c) <- ne();
country(c) <- country(cy());
APPLY;
}
EXPORT JSON FROM code = '0', message = 'OK';
}
Так как свойство имеет название createCity
и расположено в модуле с пространством имен Location
, то url, на котором будет принят запрос, имеет следующий вид:
http://localhost:7651/exec?action=Location.createCity
Body HTTP-запроса будет передан параметром с типом FILE
. В локальные свойства cy
и ne
, считываются значения из параметров countryId
и name
соответственно.
Если не находится страна с соответствующим кодом, то формируется JSON файл с содержанием, описанном в предыдущем примере, и вызывается оператор RETURN
, чтобы прервать выполнение. В качестве ответа, по умолчанию, используется значение, хранящееся в свойстве exportFile
.
В случае, если все действия были завершены успешно, то формируется соответствующий о твет с сообщение ОК.
Пример 3
Условие
Задана логика заказов книг.
CLASS Book 'Книга';
id 'Код' = DATA STRING[10] (Book) IN id;
name 'Наименование' = DATA ISTRING[100] (Book) IN id;
book (STRING[10] id) = GROUP AGGR Book b BY id(b);
CLASS Order 'Заказ';
date 'Дата' = DATA DATE (Order);
number 'Номер' = DATA STRING[10] (Order);
CLASS OrderDetail 'Строка заказа';
order 'Заказ' = DATA Order (OrderDetail) NONULL DELETE;
book 'Книга' = DATA Book (OrderDetail) NONULL;
nameBook 'Книга' (OrderDetail d) = name(book(d));
quantity 'Количество' = DATA INTEGER (OrderDetail);
price 'Цена' = DATA NUMERIC[14,2] (OrderDetail);
FORM order 'Заказ'
OBJECTS o = Order PANEL
PROPERTIES(o) date, number
OBJECTS d = OrderDetail
PROPERTIES(d) nameBook, quantity, price, NEW, DELETE
FILTERS order(d) == o
EDIT Order OBJECT o
;
FORM orders 'Заказы'
OBJECTS i = Order
PROPERTIES(i) READONLY date, number
PROPERTIES(i) NEWSESSION NEW, EDIT, DELETE
;
NAVIGATOR {
NEW orders;
}
Нужно отправить на определенный url HTTP-запрос на создание заказа в формате JSON.
Решение
FORM exportOrder
OBJECTS order = Order PANEL
PROPERTIES dt = date(order), nm = number(order)
OBJECTS detail = OrderDetail
PROPERTIES id = id(book(detail)), qn = quantity(detail), pr = price(detail)
FILTERS order(detail) == order
;
exportOrder 'Отправить' (Order o) {
EXPORT exportOrder OBJECTS order = o JSON;
LOCAL result = FILE();
EXTERNAL HTTP 'http://localhost:7651/exec?action=Location.importOrder' PARAMS exportFile() TO result;
}
EXTEND FORM orders
PROPERTIES(i) exportOrder;
;
Для создания JSON с вложенными тэгами нужно создать форму с соответствующими объектами, связанными через конструкцию FILTERS
. На основе зависимостей между ними создается JSON с соответствующей структурой. В данном случае, JSON будет выглядеть следующим образом:
{
"dt":"20.08.18",
"nm":"1",
"detail":[
{
"pr":5.99,
"id":"b1",
"qn":3
},
{
"pr":6.99,
"id":"b2",
"qn":2
}
]
}
Для order
не создается свой тэг, так как значение объекта передается параметром для оператора EXPORT
.
В данном примере, ответ полученный на HTTP-запрос игнорируется.
Пример 4
Условие
Аналогично Примеру 3.
Нужно принять соответствующий HTTP-запрос и создать новый заказ в базе данных с параметрами запроса.
Решение
date = DATA LOCAL DATE();
number = DATA LOCAL STRING[10]();
id = DATA LOCAL STRING[10] (INTEGER);
quantity = DATA LOCAL INTEGER (INTEGER);
price = DATA LOCAL NUMERIC[14,2] (INTEGER);
FORM importOrder
PROPERTIES dt = date(), nm = number()
OBJECTS detail = INTEGER
PROPERTIES id = id(detail), qn = quantity(detail), pr = price(detail)
;
importOrder (FILE f) {
IMPORT importOrder JSON FROM f;
NEW o = Order {
date(o) <- date();
number(o) <- number();
FOR id(INTEGER detail) DO NEW d = OrderDetail {
order(d) <- o;
book(d) <- book(id(detail));
quantity(d) <- quantity(detail);
price(d) <- price(detail);
}
APPLY;
}
}
Для импорта соответствующего файла в формате JSON создается форма аналогичной структуры, только в качестве классов объектов используется тип INTEGER
. При импорте значения тэгов будут помещены в свойства с соответствующими именами. Свойства date
и number
не имеют параметров, так как в JSON значения для них идут на самом верхнем уровне.