Перейти к основному содержимому
Версия: 6.x

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 значения для них идут на самом верхнем уровне.

Пример 5

Условие

Аналогично Примеру 4.

Нужно отправить на определенный url HTTP-запрос на создание заказа в формате JSON, аналогичный предыдущему примеру, только обернуть все в тэг order.

Решение

GROUP order;
FORM exportOrderNew
OBJECTS o = Order
PROPERTIES IN order dt = date(o), nm = number(o)

OBJECTS detail = OrderDetail IN order
PROPERTIES id = id(book(detail)), qn = quantity(detail), pr = price(detail)
FILTERS order(detail) == o
;

exportOrderNew 'Отправить (новый)' (Order o) {
EXPORT exportOrderNew OBJECTS o = o JSON;

LOCAL result = FILE();
EXTERNAL HTTP 'http://localhost:7651/exec?action=Location.importOrderNew' PARAMS exportFile() TO result;
}

EXTEND FORM orders
PROPERTIES(i) exportOrderNew;
;

В отличие от предыдущего примера создаем группу order, при помощи оператора GROUP. При объявлении формы в эту группу записываем все свойства для заказа и объект detail. Результирующий JSON будет выглядеть следующим образом:

{
"order":{
"dt":"20.08.18",
"nm":"1",
"detail":[
{
"pr":5.99,
"id":"b1",
"qn":3
},
{
"pr":6.99,
"id":"b2",
"qn":2
}
]
}
}

Пример 6

Условие

Аналогично Примеру 5.

Нужно принять соответствующий HTTP-запрос и создать новый заказ в базе данных с параметрами запроса.

Решение

FORM importOrderNew
PROPERTIES IN order dt = date(), nm = number()

OBJECTS detail = INTEGER IN order
PROPERTIES id = id(detail), qn = quantity(detail), pr = price(detail)
;

importOrderNew (FILE f) {
IMPORT importOrderNew 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;
}
}

Точно так же как и при экспорте, добавляем все свойств и объект detail в группу order для корректного приема новой версии JSON.

Пример 7

Условие

Аналогично Примеру 3.

Нужно по HTTP GET запросу, в котором задана дата, вернуть список номеров заказов от этой даты.

Решение

FORM exportOrders
OBJECTS date = DATE PANEL

OBJECTS order = Order
PROPERTIES nm = number(order)
FILTERS date(order) = date
;

getOrdersByDate (DATE d) {
EXPORT exportOrders OBJECTS date = d JSON;
}

Url, на который следует слать HTTP запрос, будет выглядеть следующим образом: http://localhost:7651/exec?action=Location.getOrdersByDate&p=12.11.2018.

В ответ будет возвращен, например, следующий JSON :

{
"order": [
{
"nm": "42"
},
{
"nm": "65"
}
]
}

Пример 8

Условие

Аналогично Примеру 3.

Для каждого заказа существует список приложенных к нему файлов.

CLASS Attachment 'Приложение';
order = DATA Order (Attachment) NONULL DELETE;
name 'Имя' = DATA STRING (Attachment);
file = DATA FILE (Attachment);

Нужно реализовать HTTP GET запрос, который будет возвращать для переданного внутреннего идентификатора заказа его параметры и список файлов. Кроме того, нужно отдельным запросом реализовать получение содержимого конкретного файла.

Решение

FORM orderAttachments
OBJECTS o = Order
PROPERTIES(o) number, date

OBJECTS attachments = Attachment
PROPERTIES id = VALUE(attachments), name(attachments)
;

getOrderAttachments (LONG orderId) {
FOR LONG(Order o AS Order) = orderId DO {
EXPORT orderAttachments OBJECTS o = o JSON;
}
}

Для формирования HTTP запроса нужно использовать следующий url : http://localhost:7651/exec?action=getOrderAttachments&p=32178. В нем параметр p содержит внутренний идентификатор заказа.

В ответ будет возвращен, например, следующий JSON :

{
"date": "20.10.2021",
"number": "12",
"attachments": [
{
"name": "File 1",
"id": 32180
},
{
"name": "File 2",
"id": 32183
}
]
}

В атрибутах id будут содержаться внутренние идентификаторы файлов. Затем содержимое этих файлов может быть прочитано запросом по следующему url : http://localhost:7651/exec?action=getOrderAttachment&p=32180. Действие getOrderAttachment объявляется следующим образом :

getOrderAttachment (LONG id) {
FOR LONG(Attachment a AS Attachment) = id DO
exportFile() <- file(a);
}

Запрос вернет файл с Content-Type соответствующим расширению свойства file.