Выбор схемы валидации на основе содержимого сообщения#

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

Создайте две схемы валидации:

sel_schema_1.json:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "properties": {
      "lastname": {
        "type": "string"
      },
      "firstname": {
        "type": "string"
      },
      "phone": {
        "type": "string"
      },
      "version": {
         "type": "string"
      }
    },
    "additionalProperties": false,
    "required": [
      "lastname", "firstname", "version"
    ]
  }

sel_schema_2.json:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "properties": {
      "lastname": {
        "type": "string"
      },
      "firstname": {
        "type": "string"
      },
      "phone": {
        "type": "string"
      },
      "version": {
         "type": "string"
      }
    },
    "additionalProperties": false,
    "required": [
      "lastname", "firstname", "version", "phone"
    ]
  }

Как видно, две схемы отличаются только обязательностью свойства phone.

Создайте сервис, который, в зависимости от значения свойства version в объекте запроса, будет валидировать запрос либо по первой, либо по второй схеме. Если ни первая, ни вторая схема не выбрана, то запрос будет блокирован.

Добавьте в конфигурацию профиля chains еще один сервис:

- id: 4
   allowed_queries:
     - method: post
   url: /balancer$
   listen:
     - port: 20204
   modifiers:
     set_output_headers:
       - headers:
          - version $clj_version
          - failed-condition $clj_condition_failed
          - expected $clj_condition_expected_value
          - value $clj_condition_current_value
   chains:
     request_chains:
       - actions:
         - action: JsonPathExtractToVars
           params:
             expressions:
               - path: $.version
                 var: clj_version
         - action: JsonValidation
           conditions:
             - {var: $clj_version, val: "v1", operator: "="}
           params:
             validation_schema: {type: file, path: schemas/sel_schema_1.json}
         - action: JsonValidation
           conditions:
             - {var: $clj_version, val: "v2", operator: "="}
           params:
             validation_schema: {type: file, path: schemas/sel_schema_2.json}
         - action: ConditionChecker
           params:
             rules:
               - {var: $clj_version, val: "v1,v2", operator: "IN"}
         message: $clj_request_body
   upstream_group_id: 1
   upstream_groups:
     - id: 1
       servers:
         - server: 127.0.0.1:30001
       rewrite_uri:
        - from: /balancer
          to: /test

Полученная конфигурация:

Существует четыре независимые цепочки действий — в первой попытаемся извлечь из приходящего объекта свойство version и поместить его в переменную clj_version. Далее идут две цепочки для валидации сообщения в зависимости от результата проверки условия на значение версии. И наконец, четвертая цепочка состоит из единственного корневого действия ConditionChecker, который блокирует выполнение запроса, в том случае, если значение версии ни v1, ни v2. Также был добавлен вывод значений переменных в заголовки ответа клиента со значениями версии, невыполненного условия, ожидаемого и реальных значений. Три последних переменных будут заполнены, если действие ConditionChecker вернет отрицательный результат.

Скопируйте обе схемы в каталог /sowa/profile_storage/custom/chains/schemas, остановите, сконфигурируйте и запустите профиль.

Проверка работоспособности:

  1. Отправьте запрос соответствующий версии 1:

    bash-4.2$ curl -v  http://localhost:20204/balancer --data '{"version": "v1", "lastname": "Ivanov", "firstname": "Ivan"}'
    

    Получен положительный ответ: d38

  2. Отправьте запрос, соответствующий версии v2, но без обязательного свойства phone:

    bash-4.2$ curl -v  http://localhost:20204/balancer --data '{"version": "v2", "lastname": "Ivanov", "firstname": "Ivan"}'
    

    Запрос заблокирован: d39

  3. Отправьте запрос с неподдерживаемым значением version:

    bash-4.2$ curl -v  http://localhost:20204/balancer --data '{"version": "v3", "lastname": "Ivanov", "firstname": "Ivan"}'
    

    Запрос заблокирован: d40