# ApiRoute

Данный узел служит для описания интерфейса конкретного эндпоинта. Интерфейс схож с [RequestStep](https://docs-ru.testmace.com/0.0.1-beta.14/node-types/requeststep) узлом. Это и не удивительно - в обоих случаях мы имеем дело с HTTP-запросами.

Основные возможности данного типа узлов:

* Возможность описания http-заголовков, query параметров, body параметров запроса и HTTP-кодов, HTTP-заголовков, body параметров ответа
* Использование типов для описания каждого из заголовков, query параметров, body параметров. Поддерживаются следующие типы: `string`, `number`, `integer`, `boolean`, `array` и `object`.
* Добавление описаний для каждой из сущностей
* Поддержка описания нескольких параметров тела запроса (в зависимости от content-type)
* Поддержка описания нескольких возможный ответов от сервера
* Создание запроса из описания
* Автодополнение урлов, HTTP-заголовков, query параметров и body параметров в [RequestStep](https://docs-ru.testmace.com/0.0.1-beta.14/node-types/requeststep) узлах.

## Обзор интерфейса

Для создание **ApiRoute** узла необходимо в контекстном меню [ApiFolder](https://docs-ru.testmace.com/0.0.1-beta.14/node-types/api-description/apifolder) узла выбрать **Add node** -> **ApiRoute.**

### **Вид узла в дереве проекта**

В дереве **ApiRoute** узел выглядит следующим образом:

![Вид ApiRoute узла в дереве проекта](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsjdLErhFxCQUpVzR%2Far_1.png?alt=media\&token=21b635ae-a97e-4358-b8f2-c2c95028108c)

В качестве иконки у данного вида узла выступает название HTTP-метода. Контекстное меню выглядит следующим образом:

![Контекстное меню ApiRoute узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMslz8Y5XicOHnnV8p%2Far_2.png?alt=media\&token=faa4b280-b90e-4ec8-911f-8080e90ce282)

* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название NodeName \[Copy \[number]].
* **Remove node.** Удалить узел.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

### Интерфейс вкладки

Вкладка **ApiRoute** узла выглядит следующим образом:

![Вкладка ApiRoute узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMspLCONT78JfocOc6%2Far_3.png?alt=media\&token=a997d9f9-afcf-4903-bb20-8fd792925559)

#### Области общих параметров запроса

Рассмотрим подробнее верхнюю часть данной вкладки:

![Верхняя часть таба ApiRoute узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsscrBJx53fsqf00u%2Far_4.png?alt=media\&token=8029abe1-0053-409c-a01d-1c769ce21204)

На скрине обозначены следующие области:

1. Http-метод. Данный список совпадает со списком методов из [RequestStep](https://docs-ru.testmace.com/0.0.1-beta.14/node-types/requeststep) узла
2. Url с поддержкой [механизма переменных](https://docs-ru.testmace.com/0.0.1-beta.14/variables/variables)
3. Кнопка открытия [диалога работы с переменными](https://docs-ru.testmace.com/0.0.1-beta.14/variables/user-variables)
4. Кнопка создания запроса из текущего описания API
5. Текстовое описание запроса

#### Область описания параметров запросов

В левой нижней части расположена область описания запроса. Она разделена на 3 вкладки: **Headers**, **Query parameters** и **Body** для редактирования HTTP-заголовков, query параметров и параметров тела запроса соответственно.

Рассмотрим вкладку **Headers**. Ее содержимое представлено в табличном виде. Для редактирования заголовков доступны следующие поля:

* Название заголовка
* Тип значения заголовка (список типов описан выше)
* Описание

Поддерживаются все стандартные операции.

Вкладка **Query Parameters** используется для редактирования query параметров, в остальном по функционалу идентична вкладке **Headers**.

Как уже было сказано, в **ApiRoute** узле можно описать несколько тел для одного и того же запроса. Например, по одному и тому же эндпоинту могут приниматься как данные с `Content-Type` равным `application/json`, так и с `application/xml`. Вкладка **Body** разделена как раз по `content-type` на вкладки и имеет следующий вид:

![Вид вкладки Body интерфейса описания запроса](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsvmecyriXA8KhPQP%2Far_5.png?alt=media\&token=10f32ea0-49d8-49ae-8473-8d94a367ad3e)

На скрине отмечены следующие области:

1. Кнопка редактирования текущего `content-type`. При нажатии на нее данное поле подменяется на текстовое поле, где можно ввести интересующий `content-type`.
2. Кнопка удаления тела запроса
3. Кнопка добавления тела запроса
4. Текущий `content-type` узла
5. Область редактирования тела запроса

Область редактирования тела запроса меняется в зависимости от `content-type` по следующему правилу: если `content-type` равен `application/x-www-form-urlencoded` или `multipart/form-data`, то область редактирования принимает табличный вид (аналогичный табличной области в **Headers** вкладке), в противном случае - текстовый как на скрине выше. В текстовой области в качестве формата описания используется [OpenAPI](https://swagger.io/specification/#requestBodyObject).

#### Область описания параметров запросов

В правой нижней области интерфейса вкладки **ApiRoute** узла расположена области редактирования ответов от сервера. Как уже было сказано, TestMace поддерживает описание нескольких ответов в рамках одного эндпоинта. Интерфейс данной области выглядит следующим образом:

![Интерфейс редактирования ответов сервера](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMszNK7ApEdzbaBel_%2Far_6.png?alt=media\&token=b6ff2068-1344-4527-95e0-71d17a081074)

Данный интерфейс разделен на вкладки, отдельно для каждого ответа. В рамках вкладки каждого ответа можно редактировать код ответа, описание, а также HTTP-заголовки и тела ответа, интерфейсы которых идентичны таковым из области запроса.

## Интеграция с RequestStep узлом

TestMace имеет интеграцию с **ApiRoute** узлами в **RequestStep** узлах. На данный момент эта интеграция проявляется в автодополнении url, HTTP-заголовков, query параметров, параметров тела запросов **RequestStep** узлов. Причем, для url-ов в автодополнении участвуют всех url-ы **ApiRoute** узлов, тогда как для остальных параметров автодополнение работает по следующему алгоритму:

* Берутся метод и url данного **RequestStep** узла
* Ищутся все **ApiRoute** узлы с такими url и методом
* Осуществляется поиск по искомому параметру (например, по HTTP-заголовку) среди найденных **ApiRoute** узлов

## Файловое представление

**ApiRoute** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат.

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of ApiRoute node",
      "const": "ApiRoute",
      "type": "string"
    },
    "url": {
      "type": "string",
      "default": ""
    },
    "method": {
      "$ref": "#/definitions/RequestMethod"
    },
    "description": {
      "type": "string",
      "default": ""
    },
    "requests": {
      "$ref": "#/definitions/ApiRequests",
      "description": "List of requests"
    },
    "responses": {
      "description": "List of responses",
      "type": "array",
      "items": {
        "$ref": "#/definitions/ResponseParameters"
      },
      "default": []
    },
    "children": {
      "description": "List of children names",
      "type": "array",
      "items": {
        "type": "string"
      },
      "default": []
    },
    "variables": {
      "$ref": "#/definitions/NodeVariables",
      "description": "Node variables dictionary"
    },
    "name": {
      "description": "Node name",
      "type": "string"
    }
  },
  "required": [
    "children",
    "description",
    "method",
    "name",
    "requests",
    "responses",
    "type",
    "url",
    "variables"
  ],
  "definitions": {
    "RequestMethod": {
      "enum": [
        "DELETE",
        "GET",
        "OPTIONS",
        "PATCH",
        "POST",
        "PUT"
      ],
      "type": "string"
    },
    "ApiRequests": {
      "type": "object",
      "properties": {
        "queryParameters": {
          "description": "List of query parameters",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "headers": {
          "description": "List of headers",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "cookies": {
          "description": "List of cookies",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "bodies": {
          "description": "List of bodies",
          "type": "array",
          "items": {
            "$ref": "#/definitions/RequestParameters"
          },
          "default": []
        }
      },
      "required": [
        "bodies",
        "cookies",
        "headers",
        "queryParameters"
      ]
    },
    "QueryParameter": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "type": {
          "enum": [
            "array",
            "boolean",
            "integer",
            "number",
            "object",
            "string"
          ],
          "type": "string"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "name",
        "type"
      ]
    },
    "RequestParameters": {
      "type": "object",
      "properties": {
        "contentType": {
          "type": "string"
        },
        "schema": {
          "anyOf": [
            {
              "$ref": "#/definitions/SchemaRef"
            },
            {
              "$ref": "#/definitions/OneOf"
            },
            {
              "$ref": "#/definitions/AllOf"
            },
            {
              "$ref": "#/definitions/AnyOf"
            },
            {
              "$ref": "#/definitions/ObjectMember"
            },
            {
              "$ref": "#/definitions/ArrayMember"
            },
            {
              "$ref": "#/definitions/ScalarMember"
            }
          ]
        }
      },
      "required": [
        "contentType",
        "schema"
      ]
    },
    "SchemaRef": {
      "type": "object",
      "properties": {
        "$ref": {
          "type": "string"
        }
      },
      "required": [
        "$ref"
      ]
    },
    "OneOf": {
      "type": "object",
      "properties": {
        "oneOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "oneOf"
      ]
    },
    "AllOf": {
      "type": "object",
      "properties": {
        "allOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "allOf"
      ]
    },
    "AnyOf": {
      "type": "object",
      "properties": {
        "anyOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "anyOf"
      ]
    },
    "ObjectMember": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "object"
          ]
        },
        "properties": {
          "$ref": "#/definitions/SchemaMember"
        },
        "required": {
          "type": "boolean"
        },
        "additionalProperties": {
          "$ref": "#/definitions/ScalarMember"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "SchemaMember": {
      "type": "object",
      "additionalProperties": {
        "anyOf": [
          {
            "$ref": "#/definitions/SchemaRef"
          },
          {
            "$ref": "#/definitions/OneOf"
          },
          {
            "$ref": "#/definitions/AllOf"
          },
          {
            "$ref": "#/definitions/AnyOf"
          },
          {
            "$ref": "#/definitions/ObjectMember"
          },
          {
            "$ref": "#/definitions/ArrayMember"
          },
          {
            "$ref": "#/definitions/ScalarMember"
          }
        ]
      }
    },
    "ArrayMember": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "array"
          ]
        },
        "items": {
          "anyOf": [
            {
              "$ref": "#/definitions/SchemaRef"
            },
            {
              "$ref": "#/definitions/OneOf"
            },
            {
              "$ref": "#/definitions/AllOf"
            },
            {
              "$ref": "#/definitions/AnyOf"
            },
            {
              "$ref": "#/definitions/ObjectMember"
            },
            {
              "$ref": "#/definitions/ArrayMember"
            },
            {
              "$ref": "#/definitions/ScalarMember"
            }
          ]
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "items",
        "type"
      ]
    },
    "ScalarMember": {
      "type": "object",
      "properties": {
        "type": {
          "$ref": "#/definitions/ScalarSchemaType"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "ScalarSchemaType": {
      "enum": [
        "boolean",
        "integer",
        "number",
        "string"
      ],
      "type": "string"
    },
    "ResponseParameters": {
      "type": "object",
      "properties": {
        "code": {
          "description": "Http-code (e.g. 200, 404)",
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "headers": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "content": {
          "$ref": "#/definitions/RequestParameters",
          "description": "Response body"
        }
      },
      "required": [
        "code",
        "content"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```
