# Маршруты и тестовые данные (/ru/docs/mocks/routes)

Маршрут — это метод, путь и то, что мок отвечает по нему. Создавайте маршруты вручную, когда спецификации ещё нет,
когда для разработки или тестов нужно несколько эндпоинтов или когда путь должен отвечать иначе, чем по
спецификации. Тела пишутся в том виде, в каком отправляются: JSON, XML или текст, и могут содержать тестовые данные,
которые создаются заново при каждом запросе.

Маршруты, созданные вручную, отвечают после [маршрутов на JavaScript](/docs/mocks/scripted-routes) мока и до
операций его спецификации, если он её обслуживает. См.
[какой ответ получает запрос](/docs/mocks#which-response-a-request-gets).

## Создание маршрута [#making-a-route]

На [странице «Моки»](/docs/mocks) создайте мок командой **Новый мок** (в нём сразу есть маршрут `GET /users` с пятью
тестовыми пользователями) или откройте любой мок. Карточка **Маршруты** перечисляет его маршруты:

- Флажок отключает маршрут, не удаляя его; отключённый маршрут ничего не отвечает.
- Щёлкните маршрут, чтобы изменить его под списком.
- **Добавить маршрут** добавляет новый после выбранного.
- Щёлкните маршрут правой кнопкой, чтобы выбрать **Дублировать**, **Создать запрос**, **Скопировать адрес** (пока мок
  запущен), **Переместить вверх**, **Переместить вниз** и **Удалить маршрут**.

Каждое изменение сохраняется сразу, и запущенный мок сразу отвечает по-новому. **Правка › Отменить** отменяет любое
изменение, в том числе удаление маршрута. Если у двух включённых маршрутов один метод и путь, карточка предупреждает:
отвечает только первый.

<Shot id="mocks-route-editor" alt="Редактор маршрута GET /users/{id}: метод, путь и описание, ответы 200 OK (по умолчанию) и 404 Not found, а у ответа OK — тип содержимого, заголовок X-Request-Id со значением {{$randomUUID}} и тело JSON с request.params.id и тестовыми значениями" />

### Метод, путь и описание [#method-path-and-summary]

- **Маршрут**: метод (**GET**, **POST**, **PUT**, **PATCH**, **DELETE**, **HEAD**, **OPTIONS** или **ANY** для любого
  метода) и путь. Запрос `HEAD` попадает в маршрут **GET**, без тела.
- **Параметры пути** записываются как `{id}` или `:id`, по одному на часть пути: `/users/{id}`, `/files/{name}.json`.
  `:id` сохраняется как `{id}`. Маршрут с буквальной частью важнее маршрута с параметром, поэтому `/users/me`
  отвечает раньше `/users/{id}`.
- **Сводка** говорит, для чего маршрут. Запросы, созданные из маршрута, берут её как своё имя.

## Ответы [#responses]

У маршрута один или несколько ответов. Переключатели под **ОТВЕТЫ** выбирают между ними; **+** добавляет ответ. У
каждого ответа есть:

| Поле | Что это |
| --- | --- |
| **Имя** | Как его называют запросы и правила, например `OK` или `Not found`. В пределах маршрута имена уникальны. |
| **Статус** | Код состояния, от 100 до 999. |
| **Content-Type** | Отправляемый `Content-Type`, например `application/json` или `application/xml`; в меню рядом самые распространённые типы. Если пусто, заголовок не отправляется. От него зависит и то, как экранируются значения в теле. |
| **Заголовки** | Заголовки, отправляемые вместе с ответом. Значения могут содержать тестовые данные и части запроса, как тело. |
| **Правила** | Когда отвечает этот ответ, а не ответ по умолчанию. См. [выбор ответа](#choosing-a-response). |
| **Тело** | Что отправляется, с номерами строк и подсветкой для JSON, XML и HTML. |

Ответ с галочкой — ответ маршрута **По умолчанию**; **Сделать по умолчанию** у другого ответа меняет его. Кнопка с
корзиной удаляет ответ.

### Выбор ответа [#choosing-a-response]

Запрос к маршруту получает в таком порядке:

1. Ответ, который он просит: заголовок `Prefer: example=Not found` или `Prefer: code=404` либо заголовки Postman
   `x-mock-response-name` и `x-mock-response-code`.
2. Первый ответ, у которого выполняются все правила.
3. Ответ маршрута по умолчанию: тот, что вы сделали ответом по умолчанию командой **Сделать по умолчанию**,
   независимо от его правил. Если вы его не выбирали, первый ответ, правила которого не выполнились, уступает место
   первому ответу без правил, так что «409 для отправленного заказа», стоящий первым, не отвечает на все остальные
   заказы.

**Правило** смотрит на одну часть запроса:

| Правило | Имя | Пример |
| --- | --- | --- |
| **Параметр пути** | Параметр в пути | `id` равен `0` |
| **Параметр запроса** | Параметр запроса | `page` равен `*` |
| **Заголовок** | Заголовок, в любом регистре | `X-Role` равен `admin` |
| **Поле тела** | Путь по ключам в теле JSON, с числами для элементов списка; пусто для всего тела | `user.plan` равно `pro`, `items.0.sku` равно `TNT-MH-2P` |

Значение — это текст, который должна иметь эта часть. `*` означает любое значение, лишь бы оно было; пустое значение
означает, что этой части не должно быть. Ответ с несколькими правилами отвечает, только когда выполняются все. Правило
без имени пропускается, пока вы не зададите имя.

Например, маршрут `GET /users/{id}` может по умолчанию отвечать `200` с пользователем, а ответ `404` — с правилом
**Параметр пути** `id` равен `0`:

```sh
curl -i http://127.0.0.1:4010/users/42    # 200, the user
curl -i http://127.0.0.1:4010/users/0     # 404
```

<Shot id="mocks-route-rule" alt="Ответ 404 Not found маршрута GET /users/{id} с кнопкой «Сделать по умолчанию» и его правило: Параметр пути id равен 0" />

## Тела с тестовыми данными [#bodies-with-fake-data]

Всё, что стоит в `{{ }}` в теле или значении заголовка, подставляется, когда приходит запрос, так что каждый запрос
может получать новые данные. Остальное тело отправляется так, как вы его написали.

```json
{
  "id": "{{request.params.id}}",
  "name": "{{$randomFullName}}",
  "email": "{{$randomEmail}}",
  "company": "{{$randomCompanyName}}",
  "joined": "{{$randomDatePast}}"
}
```

### Тестовые значения [#fake-values]

`{{$randomFirstName}}`, `{{$randomEmail}}`, `{{$randomCity}}`, `{{$randomPrice}}`, `{{$randomUUID}}` и около 120
других: имена и профессии, интернет, адреса, телефоны, компании, финансы, продукты, даты, слова, lorem ipsum, файлы,
изображения и базы данных. Имена взяты из динамических переменных Postman, поэтому шаблоны, написанные для Postman,
работают и здесь. Некоторые принимают аргументы: `{{$randomInt(1, 100)}}`, `{{$randomPrice(5, 50)}}`,
`{{$randomLoremWords(5)}}`, `{{$randomElement(active, paused, closed)}}`. Все значения перечислены в
[динамических значениях](/docs/reference/dynamic-values#fake-data).

**Вставить значение** над телом подставляет тестовое значение туда, где стоит курсор; в разделе **Тестовые данные**
значения сгруппированы.

Те же значения работают и в запросах, где создаются при каждой отправке. См.
[динамические значения](/docs/requests/dynamic-values).

### Части запроса [#parts-of-the-request]

| Токен | Что это |
| --- | --- |
| `{{request.params.id}}` | Параметр пути. |
| `{{request.query.page}}` | Параметр запроса; пусто, если его нет. |
| `{{request.headers.X-Trace}}` | Заголовок, в любом регистре. |
| `{{request.body.user.name}}` | Поле тела JSON по пути из ключей (`items.0.sku` для элемента списка). Текст как есть; числа, `true`, `false`, объекты и списки как JSON. |
| `{{request.body}}` | Всё тело как текст. |
| `{{request.method}}` | Метод, например `POST`. |
| `{{request.path}}` | Путь, например `/users/42`. |

**Вставить значение › Запрос** содержит их вместе с параметрами пути самого маршрута.

### Списки [#lists]

`{{#repeat 10}}` … `{{/repeat}}` записывает то, что между ними, столько раз; `{{#repeat 2 8}}` — случайное число раз
между двумя числами, выбираемое при каждом запросе. В теле JSON элементы разделяются запятыми автоматически. Внутри
`{{@number}}` — номер элемента, начиная с 1, а `{{@index}}` — начиная с 0. Повторы можно вкладывать друг в друга.

```json
[
  {{#repeat 5}}
  {
    "id": {{@number}},
    "name": "{{$randomProductName}}",
    "price": {{$randomPrice}}
  }
  {{/repeat}}
]
```

Если `{{#repeat}}` или `{{/repeat}}` стоит на строке один, пустая строка после него не остаётся.

### Экранирование [#escaping]

Значения экранируются в соответствии с тем, куда попадают, поэтому имя с кавычкой никогда не сломает ваш JSON:

- В теле JSON (`Content-Type` содержит `json`) значения внутри строки экранируются как JSON. Значение вне кавычек,
  например `{{$randomInt}}` или `{{@number}}`, подставляется как есть.
- В XML и HTML (`Content-Type` содержит `xml` или `html`) `&`, `<`, `>` и кавычки экранируются везде.
- Тройные фигурные скобки не экранируют никогда: `{{{request.body}}}` вставляет тело запроса в формате JSON как JSON.

```json
{ "received": {{{request.body}}}, "at": "{{$isoTimestamp}}" }
```

Токены, которых Echolot не знает, остаются так, как вы их написали. Значение, которое не удалось создать, например
`{{$randomInt(9, 1)}}`, тоже остаётся как написано, а [журнал](/docs/mocks#the-log) объясняет почему. Тело
ограничено 16 МБ, а повтор — 10 000 элементов.

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

### Фиксированные данные: «Сгенерировать» [#fixed-data-generate]

Значения в `{{ }}` дают новые данные при каждом запросе. Чтобы отвечать каждый раз одними и теми же данными, нажмите
**Сгенерировать…** над телом:

- С флажком **Создать список: тело — один элемент** тело становится списком JSON с таким числом элементов
  (**Количество**), каждый из которых создан из тела.
- Без него значения тела подставляются один раз.

**Сгенерировать** заменяет тело результатом; **Правка › Отменить** возвращает шаблон. Из Терминала то же самое делает
[`echolot fake`](/docs/cli/fake).

## Запросы из маршрутов [#requests-from-routes]

**Создать запросы** в карточке **Маршруты** создаёт папку с названием мока и запросом для каждого включённого
маршрута; **Создать запрос** в контекстном меню маршрута создаёт запрос для этого маршрута. Echolot открывает первый
запрос.

- В папке есть переменная `baseUrl` с адресом мока, и каждый URL начинается с неё: `{{baseUrl}}/users/{{id}}`.
  Позже направьте `baseUrl` на настоящее API, и те же запросы пойдут туда.
- Параметры пути становятся переменными запроса со значением `1`, если правило пути ответа по умолчанию не называет
  другое значение.
- Запрос получает название по сводке маршрута.
- Тело запроса маршрута передаётся вместе с ним.

### Тело запроса маршрута [#the-request-body-of-a-route]

**Тело запроса** внизу маршрута содержит тело и его **Content-Type** для запросов, созданных из маршрута, например
JSON, который принимает `POST /users`. Оно не меняет того, что отвечает мок; правила для полей тела читают то, что
запросы отправляют на самом деле.

## С агентами [#with-agents]

Когда включён набор инструментов **Моки**, маршруты создают и агенты, и [Ассистент](/docs/ai/assistant). Просто
скажите, что нужно:

- «Сделай мок с маршрутами для списка, чтения и создания заказов с тестовыми данными и запусти его.»
- «Добавь 404 в `GET /users/{id}`, когда id равен 0.»
- «Создай запросы для маршрутов мока.»

Они используют `create_mock` (с именем и маршрутами, спецификация не нужна), `save_mock_route`, `delete_mock_route`,
`generate_fake_data`, `list_fake_values` и `create_requests_from_mock`. `save_mock_route` умеет и превращать ответ из
[Истории](/docs/workspaces/history) в маршрут; то, что он копирует, скрывается так же, как всё, что читают агенты.
Когда агент удаляет маршрут, он сначала спрашивает вас. См. [Агенты](/docs/ai/agents).

## В рабочем пространстве [#in-the-workspace]

Маршруты хранятся в файле мока, `mocks/<name>.toml`, как `[[routes]]` с их `[[routes.responses]]`: их легко читать в
диффе, и ими делятся через Git. См. [файлы рабочего пространства](/docs/reference/workspace-files#mocks).
