4. Конфигурирование сервера

СМЭВ QL сервер содержит два конфигурационных файла:

  • credentials.yaml - конфигурирует представление сервера

  • application.yaml - конфигурирует поведение сервера

Состав настроек credentials.yaml:

version: 1.0.0
system:
    mnemonic: smev_ql_mnemonic
    instance: smev_ql_instance

5. Язык и синтаксис

5.1. Моделирование

Для моделирования документного слоя данных в спецификации выбран язык разметки YAML.

5.2. Запросы и ответы

Для написания запросов, а также в качестве сериализатора ответов, спецификация определяет использование JSON.

6. Типизация

Фактические типы данных наследуют типы данных JSON (включая NULL):

  • string;

  • number;

  • object;

  • array;

  • boolean;

  • null.

6.1. Типы данных в модели и приведение типов

В описании модели допускается указание фактического типа данных атрибута ресурса вторым элементом массива type. Указание является опциональным, по умолчанию подразумевается неограниченный STRING.

Пример из описания модели:

fields:
  id:
    name: Идентификатор записи
    type:
      - number
      - SHORT
    length: 20
    nullable: not NULL
    key: PRIMARY

В качестве второго уточняющего типа следует применять типы НСУД:

  • STRING;

  • DOUBLE;

  • FLOAT;

  • BOOLEAN;

  • BYTE (не поддерживается на витрине);

  • BINARY;

  • BIG_DECIMAL (не поддерживается на витрине);

  • LONG;

  • INTEGER;

  • SHORT;

  • DATE;

  • TIME;

  • TIMESTAMP.

7. Моделирование данных

Модели данных описываются в формате YAML в папке проекта models согласно спецификации СМЭВ QL.

7.1. Структура базовой модели

Базовая модель должна ставиться впереди общего файла моделей, так как от ее алиасов наследуется элементы пользовательских моделей. Описание базовой модели данных в формате YAML имеет следующую структуру:

default_string: &ds
name: Строка
type:
    - string
    - STRING
length: 0
nullable: NULL
key: NONE
source: NONE

default_number: &dn
name: Число
type:
    - integer
    - INTEGER
length: 0
nullable: NULL
key: NONE
source: NONE

primary_key: &pk
name: Ключ
type:
    - string
    - STRING
length: 0
nullable: NULL
key: PRIMAY
source: NONE

base_model: &base_model
default_fields: &default_fields

7.2. Структура модели данных

Каждая модель представляет из себя YAML-файл, который должен быть соединен с базовой моделью для прохождения валидации.

Первый блок модели определяет ее мета-данные и атрибутивный состав.

Мета-данные и поля модели

resources:
# slots — техническое название модели, по нему производятся все связи
- slots: *base_model
# значение name — название модели на русском языке
    name: Слоты
# fields — список полей модели
    fields:
# список полей может включать перечень полей из default_fields
    <<: *default_fields
# поля по-умолчанию наследуются от ds (default_string) из базовой модели
    id: *ds
    resource_id: *ds
# у поля может быть переопределен source (по-умолчанию у каждого поля источник всей модели)
    type: *ds
        source:
        field: tag_type
    age: *ds
        source:
        field: tag_age
    visitTime: *ds
    duration: *ds
    status: *ds
    create_ts: *ds
    update_ts: *ds
    update_ts: *ds

Второй блок модели описывает связи моделей друг с другом через ключи primary_key и foreign_key.

Ключи могут быть составными (описывается массивом), ключи не обязательно должны быть ключами из БД.

Связи имеют два типа:

  1. belongs_to

  2. has_many (один ко многим)

Связи модели

# Блок connections описывает связи модели (по названию) через явно указываемых два ключа
    connections:
    belongs_to:
        - resource:
            primary_key: [ id ]
            foreign_key: [ resource_id ]
    has_many:
        - book:
            primary_key: [ id ]
            foreign_key: [ slot_id ]
        - unaccessible_period:
            primary_key: [ resource_id, type ]
            foreign_key: [ resource_id, type ]

Блок ограничений и разрешений использования условий поиска.

Связи модели

# Блок conditions описывает ограничения и разрешения на использование условий поиска
    conditions:
    allowed: [id, name] # если заполнено, то поиск разрешен только по этим полям и полям с ключами
    denied: [snils] # если заполнено, то поиск запрещен по этим ключам
    always: # наличие условий в блоке always должно ко всем запросам ресурса добавлять эти условия, если указаны в запросе, то перетирать
        - region: ["=", "77"]
        - blocked: ["=", true]

Блок — extract, описывает названия source из которого нужно извлекать модель и ее таблицу.

Источники модели

extract:
source:
- name: prostore
    table: misdm.slots

Источники по условиям

В блоке c указанием источника в модели допускается указание условий его выбора через блок conditions. Блок conditions содержит массив условий применения источника на основании значений полученных в запросе атрибутов:

extract:
  source:
    - name: prostore1
      table: misdm.slots
      conditions:
        # попадание в промежуток
        - range:
            field: age
            from: 0
            to: 2
        - eq:
            field: color
            not: "blue"
    - name: prostore2
      table: misdm.39slots
      conditions:
        # ограничения по (не)равенству
        - eq:
            field: resource_id
            is: 1
    - name: prostore3
      table: misdm.39slots
      conditions:
        # ограничения по наличию в источнике
        - eq:
            field: snils
            extract:
            source: redis
            table: default_table
            key: resource_hashed_id
            algorithm: md5
            # select count(*) > 0 from offices.offices where resource_hashed_id = ?
            # параметр: md5(snils)
            is: true
    - name: prostore_default
      table: misdm.39slots
      conditions:
        - fallback: true

7.3. Загрузка

Модели данных считываются, валидируются и загружаются в память из папки models при запуске СМЭВ QL сервера.

По-умолчанию используется версия model, на которую ссылается symlink current, при его отсутствии по-умолчанию считается старшая версия.

Примечание

Модели и версии, начинающиеся с подчеркивания (_) НЕ загружаются, они находятся в стадии проектирования.

7.4. Guard-атрибуты

Для ограничения возможности получения некоторых атрибутов без предварительного предоставления их же (или дополнительных) значения, извлекающим необходимо определить атрибуты-ограничители в блоке guard.

Пример:

fields:
    <<: *default_fields
    first_name: *ds
    last_name:
        <<: *ds
        guard: [last_name]
    snils:
        <<: *ds
        guard: [last_name first_name snils]

В примере извлечение first_name не ограничивается. Для получения last_name фамилия должна быть передана в блоке conditions, а для получения snils в conditions должны присутствовать фамилия, имя и сам СНИЛС.

8. Запросы

Запросы к серверу выполняют методом POST и содержат в теле JSON-объект, состоящий из обязательных блоков:

  • Блок Credentials;

  • Блок Query;

Также пространстве методов server находятся методы, помогающие эксплуатации корректно конфигурировать хранилища данных относительно модели СМЭВ QL.

8.1. Блок Credentials

"credentials":{
    "system":{
        "mnemonic":"117bed7f-1c07-4079-a446-1161588db4e5",
        "instance_id":"ccb4a88f-f44b-43e7-8a97-3e45c8345e90",
        "user_id":"5ed38461-0907-486a-930a-7b443482932c"
    },
    "request":{
        "id":"df5a0073-c6be-4d8c-8eb2-9b2f4188a429",
        "sub_id":"0cdb59ce-224b-4118-8da1-c5ea08a5d955",
        "name":"driver_data",
        "purpose_id":"ed1170f1-3caa-4985-aa38-c9c5a190b770",
        "audit":"false",
        "audit_id":"fc1048fe-323d-4eeb-92df-5710b3d1d100",
        "audit_token":"39e47aac-45d2-44c1-8c26-2d9b28b1703b"
    },
    "signature":{
        "digest": null,
        "signature": null
    }
}

8.2. Блок Query

{
    "query": {
        "office": {
            "conditions": {
                "phone": "(347) 246-53-00"
            },
            "attributes": [
                "id",
                "phone",
                "name"
            ],
            "cabinet": {
                "conditions": {
                    "available": true
                },
                "attributes": [
                    "number",
                    "name",
                    "seats"
                ],
                "online_room": {
                    "conditions": {
                        "public": true,
                        "software": "zoom"
                    },
                    "attributes": [
                        "url"
                    ]
                },
                "parking": {
                    "conditions": {
                        "free": true,
                        "available": true
                    },
                    "attributes": [
                        "number",
                        "floor"
                    ]
                }
            }
        }
    }
}

8.2.1. Условия фильтрации Conditions

Объединение условий только по and (MVP)

Операции сравнения (op):

  • = (по умолчанию)

  • >

  • >=

  • <

  • <=

  • in

  • like (на перспективу)

Условия сравнения применимы к численным типам, датам, временам и таймштампам.

Варианты определения условий фильрации:

По равенству

{
    "query": {
        "office": {
            "conditions": {
                "phone": "(347) 246-53-00"
            }
        }
    }
}

На основе сравнения, краткая запись

{
    "query": {
        "office": {
            "conditions": {
                "area": [">","130"]
            }
        }
    }
}

На основе сравнения, полная запись

{
    "query": {
        "office": {
            "conditions": {
                "area": {
                    "op": ">",
                    "value": "130"
                }
            }
        }
    }
}

Комплексное условие

{
    "query": {
        "office": {
            "conditions": {
                "area": [">","130"],
                "floor": ["in", [1, 2]]
            }
        }
    }
}

OR (ИЛИ) в условиях

В conditions СМЭВ QL запроса поддерживается возможность указывать логический ИЛИ через зарезервированное слово or.

В блок or необходимо передать массив объектов, содержащих условия в свою очередь объединённые логическим И (AND).

Все условия, находящиеся на одном уровне с or группируются через логическое И (AND), как при обычном СМЭВ QL Запросе.

Пример:

"conditions": {
"lastname": "П",
"middlename": "И",
"birthdate": "2021-11-29 00:00:00",
"or": [
    {
        "vin": "в1"
    },
    {
        "vin2": "в2",
        "model": "bmw"
    }
],
"fetch": {
    "order": [["id", "ASC"], ["number", "DESC"]], // ASC default
    "page": [2, 10] // limit 10 offset 10
}
}

Условия описанного выше запроса (без учета fetch) соберутся в следующую конструкцию:

...
WHERE
        (lastname = 'П' AND middlename = 'И' AND birthdate = '2021-11-29 00:00:00')
    OR
        (vin ='в1')
    OR
        (vin2='в2' AND model = 'bmw')
...

8.2.2. Сортировка и пагинация

В блоке conditions опционально можно добавить блок fetch, в котором указывать условия сортировки и выбора страниц.

Пример блока:

"conditions": {
"lastname": "П",
"middlename": "И",
"birthdate": "2021-11-29 00:00:00",
"fetch": {
    "order": [["id", "ASC"], ["number", "DESC"]], // ASC default
    "page": [2, 10] // limit 10 offset 10
}
}

Если порядок сортировки не указан, то применяется ASC.

Если не указаны страницы, то по умолчанию всегда устанавливается первая страница с лимитом, равными параметру default блока pagination в файле конфигураций application.yaml.

Если запрашивается элементов на страницу больше, чем значение max, то должно использоваться дефолтное значение.

pagination:
    default: 100 //количество элементов на странице по умолчанию
    max: 1000 //максимальное количество элементов на странице

8.3. Эксплуатационные запросы

В пространстве методов server находятся методы, помогающие эксплуатации корректно конфигурировать хранилища данных относительно модели СМЭВ QL.

Метод возврата списка обязательных для создания индексов: GET server/indexes/required

В ответе должен возвращаться JSON с полями, используемыми в связях моделей (connections) и блоке conditions.allowed моделей, если они определены (conditions)

{
    "server": {
        "mnemonic": "#mnemonic",
        "instance": "#instance"
    },
    "indexes": {
        "connections": [{
                "source": "#source_name2",
                "table": "#table_name2",
                "fields": ["#field_name1", "#field_name2"]
            },
            {
                "source": "#source_name2",
                "table": "#table_name2",
                "fields": ["#field_name1", "#field_name2"]
            }
        ],
        "conditions": [{
                "source": "#source_name2",
                "table": "#table_name2",
                "fields": ["#field_name1", "#field_name2"]
            },
            {
                "source": "#source_name2",
                "table": "#table_name2",
                "fields": ["#field_name1", "#field_name2"]
            }
        ]
    }
}

9. Обработка запросов

9.1. Логирование мета-данных

У каждого запроса логируются данные из блока credentials в info и выше.

Формат строчки лога:

{
    "level": "info",
    "time": "2000-01-01T01:01:01.111Z",
    "name": "#{smevql_server_name}.request",
    "system": {
        "mnemonic": "117bed7f-1c07-4079-a446-1161588db4e5",
        "instance_id": "ccb4a88f-f44b-43e7-8a97-3e45c8345e90",
        "user_id": "5ed38461-0907-486a-930a-7b443482932c"
    },
    "request": {
        "id": "df5a0073-c6be-4d8c-8eb2-9b2f4188a429",
        "sub_id": "0cdb59ce-224b-4118-8da1-c5ea08a5d955",
        "name": "driver_data",
        "purpose_id": "ed1170f1-3caa-4985-aa38-c9c5a190b770",
        "audit": "false",
        "audit_id": "fc1048fe-323d-4eeb-92df-5710b3d1d100",
        "audit_token": "39e47aac-45d2-44c1-8c26-2d9b28b1703b"
    }
}

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

{
    "level": "info",
    "time": "2000-01-01T01:01:01.111Z",
    "name": "#{smevql_server_name}.request",
    "system": {
        "mnemonic": "117bed7f-1c07-4079-a446-1161588db4e5",
        "instance_id": "ccb4a88f-f44b-43e7-8a97-3e45c8345e90",
        "user_id": "5ed38461-0907-486a-930a-7b443482932c"
    },
    "request": {
        "id": "df5a0073-c6be-4d8c-8eb2-9b2f4188a429",
        "sub_id": "0cdb59ce-224b-4118-8da1-c5ea08a5d955",
        "name": "driver_data",
        "purpose_id": "ed1170f1-3caa-4985-aa38-c9c5a190b770",
        "audit": "false",
        "audit_id": "fc1048fe-323d-4eeb-92df-5710b3d1d100",
        "audit_token": "39e47aac-45d2-44c1-8c26-2d9b28b1703b"
    },
    "source_request": {
        "id": "1cdb59ce-224b-4118-8da1-c5ea08a5d955",
        "source": "#{source_name}"
    }
}

Передача идентификаторов:

  1. source_request.id передается в queryId тела запроса в Простор.

  2. В x-request-id передается склейка {request.id};{request.sub_id};{source_request.id}

Логирование ответа

{
    "level": "info",
    "time": "2000-01-01T01:01:01.111Z",
    "name": "#{smevql_server_name}.response",
    "system": {
        "mnemonic": "117bed7f-1c07-4079-a446-1161588db4e5",
        "instance_id": "ccb4a88f-f44b-43e7-8a97-3e45c8345e90",
        "user_id": "5ed38461-0907-486a-930a-7b443482932c"
    },
    "request": {
        "id": "df5a0073-c6be-4d8c-8eb2-9b2f4188a429",
        "sub_id": "0cdb59ce-224b-4118-8da1-c5ea08a5d955",
        "name": "driver_data",
        "purpose_id": "ed1170f1-3caa-4985-aa38-c9c5a190b770",
        "audit": "false",
        "audit_id": "fc1048fe-323d-4eeb-92df-5710b3d1d100",
        "audit_token": "39e47aac-45d2-44c1-8c26-2d9b28b1703b"
    },
    "source_request": {
        "id": "1cdb59ce-224b-4118-8da1-c5ea08a5d955",
        "source": "#{source_name}"
    },
    "response": {
        "duration": "1ms",
        "code": 200,
        "result": "ok"
    }
}

9.2. Построение плана

Входные данные:

  • загруженные модели, описывающие атрибутный состав сущностей, связи между сущностями и источники;

  • запрос поступивший к серверу.

Необходимо определить набор запросов и порядок их исполнения SMQEVQL сервером, обеспечить параллельное исполнение независимых запросов.

Вид плана запроса:

plan:
level: 1
    - source: prostore1
    query: SELECT id, phone, name FROM office WHERE phone = '(347) 246-53-00';
    pk: id
    alias: offices
level: 2
    - source: prostore2
    query: SELECT id, number, name, seats FROM cabinet WHERE office_id in (@offices) AND available = 'true';
    pk: id
    alias: cabinets
    - source: prostore1
    query: SELECT id, number, floor FROM parking WHERE office_id in (@offices) free = 'true' AND available = 'true';
    pk: number, flor
    alias: parkings
level: 3
    - source: vostok7
    query: SELECT url FROM online_room WHERE cabinet_id in (@cabinets) AND public = 'true' AND software = 'zoom';
    pk: null
    alias: online_rooms

Сначала параллельно выполняются запросы первого уровня, затем запрос второго уровня на основе данных полученных на первом уровне.

Фомирование плана запроса основывается на внешнем объединении данных в сторону основной сущности.

Порядок формирования плана запроса:

  • на основе query определяется основная запрашиваемая сущность;

  • на основе query определяются вспомогательные сущности;

  • на основе query определяются conditions к основной сущности;

  • на основе query определяются conditions к вспомогательным сущностям;

  • на первом уровне плана формируется запрос к основной сущности на основе: - запрошенных атрибутов; - данных модели; - условий фильтрации.

Отмечаются поля, составляющие PK.

Первичные ключи, даже отсутствующие в атрибутах запроса к серверу должны быть в запросе к источнику.

  • формируется запрос к вспомогательным сущностям на основе: - запрошенных атрибутов; - данных модели; - условий фильтрации; - с добавлением фильрации по PK основной или предшествующей сущности.

Первичные ключи, даже отсутствующие в атрибутах запроса к серверу должны быть в запросе к источнику, за исключением терминальных запросов.

План запроса

План запроса соответсвует иерархии построенной от основной сущности на основе связей (modelconnections).

Граф план

10. Ответы

Ответы СМЭВ QL сервера представляют из себя объект JSON, схема которого определяется составом запроса.

Например для запроса:

{
"query":{
    "people":{
        "conditions":{
            "age":"<35"
        },
        "attributes":[
            "name",
            "phone",
            "vsu_code"
        ],
        "military_office":{
            "attributes":[
            "address"
            ]
        }
    }
},
"credentials":{

}
}

Ответ будет следующим:

{
"response":{
    "people":[
        {
            "name":"Иван",
            "phone":"+79011001010",
            "vsu_code":"1025",
            "military_office":[
            {
                "address":"г.Москва, ул.Угрешко"
            }
            ]
        },
        {
            "name":"Пётр",
            "phone":"+79022002020",
            "vsu_code":"1026",
            "military_office":[
            {
                "address":"г.Москва, Хилков переулок"
            }
            ]
        }
    ]
},
"credentials":{

}
}

11. Стейт-машина СМЭВ QL

СМЭВ QL содержит встроенную машину состояний для изменения объектов модели внутри витрин данных. Одновременно с этим Стейт машина может, в качестве подтверждения перехода состояния, использовать внешний источник (например ИС Электронной очереди).

Карта состояний и переходов описывается в виде YAML-файла state.yaml располагаемого в папке states/<имя-модели>/<х.х версия модели> инстанса СМЭВ QL Сервера.

Описание формата и правил карты состояний:

model: slot # имя модели
states: # массив состояний объекта
- state: available # название состояния available
    attributes: # массив атрибутов, описывающих состояние
    - name: status # состояние определятся значением атрибута status
        value: AVAILABLE # значение атрибута для описываемого состояния
    initial: true
- state: booked
    attributes:
    - name: status
        value: RECORDED
- state: reserved
    attributes:
    - name: status
        value: RESERVED
- state: cancelled
    attributes:
    - name: status
        value: CANCELED
- state: blocked
    attributes:
    - name: status
        value: BLOCKED
events: # список событий изменения состояний, из них создаются методы API
- event: book # создает метод POST /states/slot/book
    from: # массив состояний из которых возможен вызов события
    - available
    - reserved
    to: booked # в какое состояние переводится объект после события
    hooks: # массив связанных событий
    - model: book # после перевода надо вызвать событие init для модели book
        event: init
    confirm:
        source: rmis_rest # названия источника
        endpoint: /booking/book
        method: post
        body: payload # что включать в тело запроса (full|state|conditions|payload|credentials)
        accept: # условие принятия
            jsonpath: $.status.statusCode
            eq: 0 # ожидаем, что statusCode будет равен 0
- event: reserve
    from: available
    to: reserved
- event: block
    from: available
    to: blocked
- event: cancel
    from:
    - available
    - reserved
    - booked
    - blocked
    to: cancelled
    hooks:
    - model: book
        event: cancel

При наличии заполненных состояний машины СМЭВ QL Сервер генерирует API c набором HTTP-методов, отвечающих за изменение и просмотр состояний объектов:

  1. GET /states — получить карту переходов

  2. GET /states/<model-name> — получить карту переходов конкретной модели

  3. POST /states/<model-name>/<event-name> — выполнить переход состояний для модели

Запрос выполнения перехода:

POST /states/slot/book
{
    "state": {
        "conditions": {
            "id": "d9e70331-b4c0-4e96-96b6-322ac75e5188" # slot_id
        },
        "payload": {
            "bookId":"82dcac12-0a29-4fff-b9a7-8dfc84f7853d",
            "patient_Id":"23453456",
            "booking_type":"APPOINTMENT",
            "caseNumber":"73367196",
            "preliminaryReservation": false,
            "email":"email@gmail.com",
            "mobilePhone":"89150000102",
            "referral_id":"102111",
            "cards_id":"102"
        }
    },
    "credentials": {
        "system": {
            "mnemonic": "117bed7f-1c07-4079-a446-1161588db4e5",
            "instance_id": "ccb4a88f-f44b-43e7-8a97-3e45c8345e90",
            "user_id": "5ed38461-0907-486a-930a-7b443482932c"
        },
        "request": {
            "id": "df5a0073-c6be-4d8c-8eb2-9b2f4188a429",
            "sub_id": "0cdb59ce-224b-4118-8da1-c5ea08a5d955",
            "name": "request_name",
            "purpose_id": "ed1170f1-3caa-4985-aa38-c9c5a190b770",
            "audit": false,
            "audit_id": "fc1048fe-323d-4eeb-92df-5710b3d1d100",
            "audit_token": false
        }
    }
}

11.1. Спецификация интерфейса Стейт-машины

openapi: 3.0.0
x-stoplight:
id: 5i2oag6m5eq3v
info:
title: SmevQLStateMachine
version: '1.0'
description: ''
servers:
- url: 'http://localhost:3000'
paths:
/states:
    parameters: []
    get:
    summary: Get models
    tags: []
    responses:
        '200':
        description: ''
        content:
            application/x-yaml:
            schema:
                $ref: '#/components/schemas/Models'
            examples: {}
            application/xml:
            schema:
                type: object
                properties: {}
            multipart/form-data:
            schema:
                type: object
                properties: {}
            text/html:
            schema:
                type: object
                properties: {}
    operationId: get-models
    description: Retrieve the information of models
'/states/{model}':
    parameters:
    - schema:
        type: string
        name: model
        in: path
        required: true
    get:
    summary: Get model
    tags: []
    responses:
        '200':
        description: Model Found
        content:
            application/x-yaml:
            schema:
                $ref: '#/components/schemas/Model'
            examples: {}
        '400':
        description: Bad Request
        '404':
        description: Model Not Found
    operationId: get-model
    description: Retrieve the information of model
    parameters: []
'/states/{model}/{event}':
    post:
    summary: State change
    operationId: post-state
    responses:
        '200':
        description: State Updated
        content:
            plain/text:
            schema:
                type: string
            examples: {}
        '400':
        description: Bad request
        '404':
        description: Not Found
    requestBody:
        content:
        application/json:
            schema:
            $ref: '#/components/schemas/StateUpdate'
            examples: {}
        description: Post the necessary fields for the API to create a new user.
    description: Update state
    parameters: []
    parameters:
    - schema:
        type: string
        name: model
        in: path
        required: true
    - schema:
        type: string
        name: event
        in: path
        required: true
components:
schemas:
    State:
    type: object
    x-stoplight:
        id: 89f55561cae04
    properties:
        state:
        type: string
        attributes:
        type: array
        minItems: 1
        items:
            $ref: '#/components/schemas/Attribute'
        initial:
        type: boolean
    Model:
    type: object
    x-stoplight:
        id: b96a73db1e1b2
    properties:
        model:
        type: string
        states:
        type: array
        minItems: 1
        items:
            $ref: '#/components/schemas/State'
        events:
        type: array
        items:
            $ref: '#/components/schemas/Event'
    Events:
    title: Events
    x-stoplight:
        id: qdvbkmgs9xkli
    type: array
    items:
        $ref: '#/components/schemas/Event'
    States:
    $ref: '#/components/schemas/State'
    x-stoplight:
        id: wab1w6ro30nrl
    Event:
    title: Event
    x-stoplight:
        id: sr024y2v7khum
    type: object
    properties:
        event:
        type: string
        from:
        type: string
        to:
        type: string
    Models:
    title: ModelSet
    x-stoplight:
        id: e7de590d788a7
    type: array
    items:
        $ref: '#/components/schemas/ModelInstance'
    ModelInstance:
    type: object
    properties:
        model:
        type: string
        states:
        $ref: '#/components/schemas/States'
        events:
        $ref: '#/components/schemas/Events'
    ModelSet:
    type: array
    items:
        $ref: '#/components/schemas/Model'
    Attribute:
    title: Attribute
    x-stoplight:
        id: 3kiqu047734tc
    type: object
    properties:
        name:
        type: string
        value:
        type: string
    description: ''
    StateUpdate:
    title: StateUpdate
    x-stoplight:
        id: 2iyfifo0q1dt2
    type: object
    properties:
        state:
        type: object
        properties:
            conditions:
            type: object
            payload:
            type: object
        credentials:
        type: object
        properties:
            system:
            type: object
            properties:
                mnemonic:
                type: string
                instance_id:
                type: string
                user_id:
                type: string
            request:
            type: object
            properties:
                id:
                type: string
                format: uuid
                sub_id:
                type: string
                format: uuid
                name:
                type: string
                purpose_id:
                type: string
                format: uuid
                audit:
                type: boolean
                audit_id:
                type: string
                format: uuid
                audit_token:
                type: string

Пример реализации: Спецификация интерфейса Стейт-машины РМИС (OpenAPI)

openapi: 3.0.0
x-stoplight:
id: 5i2oag6m5eq3v
info:
title: SmevQLStateMachine
version: '1.0'
description: ''
servers:
- url: 'http://localhost:3000'
paths:
/states:
    parameters: []
    get:
    summary: Get models
    tags: []
    responses:
        '200':
        description: ''
        content:
            application/x-yaml:
            schema:
                $ref: '#/components/schemas/Models'
            examples: {}
            application/xml:
            schema:
                type: object
                properties: {}
            multipart/form-data:
            schema:
                type: object
                properties: {}
            text/html:
            schema:
                type: object
                properties: {}
    operationId: get-models
    description: Retrieve the information of models
'/states/{model}':
    parameters:
    - schema:
        type: string
        name: model
        in: path
        required: true
    get:
    summary: Get model
    tags: []
    responses:
        '200':
        description: Model Found
        content:
            application/x-yaml:
            schema:
                $ref: '#/components/schemas/Model'
            examples: {}
        '400':
        description: Bad Request
        '404':
        description: Model Not Found
    operationId: get-model
    description: Retrieve the information of model
    parameters: []
'/states/{model}/{event}':
    post:
    summary: State change
    operationId: post-state
    responses:
        '200':
        description: State Updated
        content:
            plain/text:
            schema:
                type: string
            examples: {}
        '400':
        description: Bad request
        '404':
        description: Not Found
    requestBody:
        content:
        application/json:
            schema:
            $ref: '#/components/schemas/StateUpdate'
            examples: {}
        description: Post the necessary fields for the API to create a new user.
    description: Update state
    parameters: []
    parameters:
    - schema:
        type: string
        name: model
        in: path
        required: true
    - schema:
        type: string
        name: event
        in: path
        required: true
components:
schemas:
    State:
    type: object
    x-stoplight:
        id: 89f55561cae04
    properties:
        state:
        type: string
        attributes:
        type: array
        minItems: 1
        items:
            $ref: '#/components/schemas/Attribute'
        initial:
        type: boolean
    Model:
    type: object
    x-stoplight:
        id: b96a73db1e1b2
    properties:
        model:
        type: string
        states:
        type: array
        minItems: 1
        items:
            $ref: '#/components/schemas/State'
        events:
        type: array
        items:
            $ref: '#/components/schemas/Event'
    Events:
    title: Events
    x-stoplight:
        id: qdvbkmgs9xkli
    type: array
    items:
        $ref: '#/components/schemas/Event'
    States:
    $ref: '#/components/schemas/State'
    x-stoplight:
        id: wab1w6ro30nrl
    Event:
    title: Event
    x-stoplight:
        id: sr024y2v7khum
    type: object
    properties:
        event:
        type: string
        from:
        type: string
        to:
        type: string
    Models:
    title: ModelSet
    x-stoplight:
        id: e7de590d788a7
    type: array
    items:
        $ref: '#/components/schemas/ModelInstance'
    ModelInstance:
    type: object
    properties:
        model:
        type: string
        states:
        $ref: '#/components/schemas/States'
        events:
        $ref: '#/components/schemas/Events'
    ModelSet:
    type: array
    items:
        $ref: '#/components/schemas/Model'
    Attribute:
    title: Attribute
    x-stoplight:
        id: 3kiqu047734tc
    type: object
    properties:
        name:
        type: string
        value:
        type: string
    description: ''
    StateUpdate:
    title: StateUpdate
    x-stoplight:
        id: 2iyfifo0q1dt2
    type: object
    properties:
        state:
        type: object
        properties:
            conditions:
            type: object
            properties:
                id:
                type: string
                format: uuid
            payload:
            type: object
            properties:
                book_id:
                type: string
                format: uuid
                patient_id:
                type: string
                booking_type:
                type: string
                case_number:
                type: string
                preliminary_reservation:
                type: boolean
                email:
                type: string
                mobile_phone:
                type: string
                referral_id:
                type: string
                cards_id:
                type: string
        credentials:
        type: object
        properties:
            system:
            type: object
            properties:
                mnemonic:
                type: string
                instance_id:
                type: string
                user_id:
                type: string
            request:
            type: object
            properties:
                id:
                type: string
                format: uuid
                sub_id:
                type: string
                format: uuid
                name:
                type: string
                purpose_id:
                type: string
                format: uuid
                audit:
                type: boolean
                audit_id:
                type: string
                format: uuid
                audit_token:
                type: string

11.1.1. Выполнение операций обновления данных в витрине

Инсерты в витрину выполняются в порядке поступления запросов.

Каждый экземпляр СМЭВ QL сервера ведет нарастающий счетчик инсертов.

Каждый экземпляр СМЭВ QL сервера создает один поток управления дельтами, который выполняет:

  1. Периодически (период конфигурируемая величина, по умолчанию 60 сек) проверяет значение счетчика числа инсертов, если значение счетчика более 0

  • Выполняет открытие и закрытие дельты с флагом immediate, ошибки открытия и закрытия дельты игнорируются. Попытка закрытия дельты выполняется независимо от успешности открытия дельты.

  • Обнуляет значение счетчика.

  1. Периодически (период конфигурируемая величина, по умолчанию 30 мин)

  • Выполняет открытие и закрытие дельты с флагом immediate, ошибки открытия и закрытия дельты игнорируются. Попытка закрытия дельты выполняется независимо от успешности открытия дельты.

Чтение данных сервером СМЭВQL выполняется с применением AS OF <maxLong>.

11.1.2. Обновление объектов через Стейт-машину

Через Стейт-машину можно обновлять записи в витрине. Для этого при конфигурировании карты состояний необходимо задать значение у event updatable: true.

При этом если требуется дать возможность обновлять только часть атрибутов, то ограничить этот список можно перечислив атрибуты в массиве updatable_attributes.

- event: reserve
  from: available
  to: reserved
  updatable: true // по умолчанию false для всех, кроме init, возможность изменять запись при переводе статуса
  updatable_attributes: [] // массив атрибутов, которые можно обновлять, пустой — можно все

Данные для обновления будут браться из блока payload запроса на смену состояния.

Для события init такое конфигурирование не требуется - по умолчанию обновления разрешены для всех атрибутов из payload.

12. Ошибки

Ошибки выводятся в блоке response:

{
"response": {
    "errors": [
    {
        "error": "Запрещен вывод атрибутов без переданного guard",
        "code": "401"
    }
    ]
},
"credentials": {

}
}

12.1. Базовые ошибки СМЭВ Ql

1ХХ Ошибки разбора запроса

  • 101 Запрос не должен называться „errors“ — Неправильное название запроса „errors“

2ХХ Ошибки модели

  • 201 Неизвестный атрибут — У ресурса не найден атрибут с соотв. именем

  • 202 Неизвестный ресурс — Ресурс с соотв. именем не зарегистрирован в модели данных

  • 203 Неизвестная связь — Не найдена связь между двумя ресурсами

  • 204 Неправильная связь — Размеры ключей не соответствуют для соединения одного ресурса с другим

3ХХ Ошибки источников

  • 301 Неизвестный источник — Не найдено описание источника данных с соотв. именем

  • 302 Неизвестный адаптер — Не найден адаптер с соотв. именем

4ХХ Ошибки доступов и ограничений

  • 401 Запрещен вывод атрибутов без переданного guard — Среди запрашиваемых атрибутов есть атрибут с невыполненными ограничениями в блоке guard (не переданы в запросе атрибуты из guard)

  • 402 Недостаточно атрибутов для выбора источника — Среди атрибутов фильтрации нет атрибутов, необходимых для выбора источника

  • 403 Запрещенные атрибуты для поиска — Среди атрибутов фильтрации есть атрибуты, указанные в блоке denied модели

  • 404 Атрибуты для поиска не разрешены — Среди атрибутов фильтрации есть атрибуты, которые не указаны в разрешающем блоке allowed модели

  • 405 Попытка переопределения фиксированных условий поиска — Среди атрибутов фильтрации есть атрибуты, которые пытаются переопределить фиксированные ограничения поиска в блоке always модели

9ХХ Прочие ошибки

  • 901 Непредвиденная ошибка — Непредвиденная ошибка