# Цепочка запросов (/ru/docs/tutorials/chain-requests)

Большинству API нужен токен, который вы получаете при входе. В этом руководстве вы сохраните токен демо-магазина в
переменную из ответа на вход, будете передавать его целой папкой через её авторизацию, возьмёте значение из одного
ответа в следующий запрос и безопасно оформите заказ с `Idempotency-Key`.

- **Время:** 15 минут.
- **Вам понадобится:** рабочее пространство из руководства [Ваше первое рабочее пространство](/docs/tutorials/first-workspace)
  с выбранным окружением **Demo** и запросом **Auth › Sign in**. В Alpenglow всё это уже собрано; откройте его, чтобы
  сравнить.
- **Вы узнаете:** про захваты из ответа, наследуемую авторизацию, динамические значения и значения ответа.

## 1. Сохраните токен из ответа на вход [#1-store-the-token-from-the-sign-in-response]

1. Откройте **Auth › Sign in** и отправьте его (<kbd>⌘</kbd><kbd>R</kbd>).
2. На вкладке **Тело** ответа переключите вид на **JSON-дерево**.
3. Наведите указатель на строку `access_token`. После значения появятся маленькие кнопки. Выберите ту, у которой в
   подсказке написано **Сохранить в переменную…**.
4. Во всплывающем окне **Сохранить в переменную**:
   - Измените имя на `token`.
   - В области действия выберите **Окружение «Demo»**: у каждого сервера свои токены.
   - Убедитесь, что отмечено **Секрет · в Связке ключей, никогда в файлах**. Для имён вроде `token` Echolot отмечает
     это сам.
   - Оставьте отмеченным **Обновлять при каждой отправке · сохраняется с этим запросом**.
5. Нажмите **Сохранить**.

Откройте вкладку **Переменные** запроса. В разделе **Из ответа** появилась строка: `token`, из **JSON**, путь
`$.access_token`, сохраняется в **Demo**, секрет. Теперь каждая успешная отправка **Sign in** записывает новый токен в
`{{token}}`. Ответ со статусом 400 и выше или без этого значения переменную не трогает. Подробности — в разделе
[захваты из ответа](/docs/requests/captures).

<Shot id="tutorials-chain-store-variable" alt="Всплывающее окно «Сохранить в переменную» над значением access_token в JSON-дереве: область действия и отмеченный флажок секрета" />

## 2. Передавайте токен из целой папки [#2-send-the-token-from-a-whole-folder]

Вместо того чтобы задавать авторизацию Bearer в каждом запросе, задайте её один раз для папки.

1. Создайте папку `Orders` (<kbd>⇧</kbd><kbd>⌘</kbd><kbd>N</kbd>).
2. Щёлкните **Orders** правой кнопкой и выберите **Настройки папки…**.
3. На вкладке **Авторизация** задайте **Тип** **Bearer-токен** и **Токен** `{{token}}`. Нажмите **Готово**.
4. Щёлкните **Orders** правой кнопкой, выберите **Новый запрос** и назовите его `List orders`. Задайте ему URL
   `{{baseURL}}/orders`.
5. Откройте его вкладку **Авторизация**. **Тип** — **Наследовать**, а в строке **Использует** сказано, что берётся
   Bearer-токен папки.
6. Отправьте его.

Вы получите три заказа Хайди: `ord_7Hk2Lw` (отправлен), `ord_8Jm4Qx` (оплачен) и `ord_5Fd9Ra` (доставлен). Каждый новый
запрос в **Orders** передаёт токен так же. Запросы начинают с **Наследовать**: берётся авторизация ближайшей папки, а
затем рабочего пространства. О других типах см. [авторизацию](/docs/requests/auth).

Если позже вы получите `401 Unauthorized`, токен истёк: он действует час. Отправьте **Sign in** ещё раз, и токен
обновится.

## 3. Прочитайте значение из другого ответа [#3-read-a-value-from-another-response]

Следующий запрос берёт id первого заказа из ответа на **List orders**, так что вам никогда не придётся копировать его
вручную.

1. В **Orders** создайте запрос `Get order`.
2. В его поле URL введите `{{baseURL}}/orders/`, а затем `{{$response`. В списке появятся динамические значения из группы
   **Ответы**. Выберите **Ответ, отфильтрованный JSONPath**.
3. В открывшейся форме задайте **Запрос** — запрос **List orders** (`orders/list-orders`) — и **JSONPath**
   `$.items[0].id`. Оставьте **Сначала отправить** в разделе **Если ответа ещё нет**. Нажмите **Готово**.

Теперь в URL лежит токен, обозначающий `{{$responseJSONPath('orders/list-orders', '$.items[0].id')}}`. Наведите на него
указатель, чтобы увидеть его текущее значение: `ord_7Hk2Lw`. Отправьте **Get order**, и вы получите этот заказ с его
позициями и доставкой. Если бы **List orders** ни разу не отправляли, Echolot отправил бы его первым.

## 4. Оформите заказ с динамическими значениями [#4-place-an-order-with-dynamic-values]

Динамические значения создаются заново при каждой отправке. Используйте два из них в новом заказе.

1. В **Orders** создайте запрос `Create order` с методом **POST** и URL `{{baseURL}}/orders`.
2. На вкладке **Тело** выберите **JSON** и введите тело. С помощью списка `{{` вставьте **Метка времени ISO 8601**:

   ```json
   {
     "lines": [
       { "sku": "TNT-MH-2P", "quantity": 1 },
       { "sku": "PCK-TIT-30", "quantity": 2 }
     ],
     "note": "Placed from Echolot at {{$isoTimestamp}}"
   }
   ```

3. На вкладке **Заголовки** добавьте заголовок `Idempotency-Key`. В качестве значения введите `{{` и выберите **UUID**
   (`{{$uuid}}`).
4. Отправьте его.

Ответ — `201 Created` с заголовком `Location` вида `/v1/orders/ord_…`, а магазин возвращает ваш `Idempotency-Key`.
В заметке указано время отправки. Демо ничего не хранит, поэтому новый заказ потом получить нельзя. Все динамические
значения собраны в [справочнике](/docs/reference/dynamic-values).

<Shot id="tutorials-chain-create-order" alt="Запрос Create order получил ответ 201 Created с заголовками ответа Location и Idempotency-Key" />

## 5. Посмотрите, что делает Idempotency-Key [#5-see-what-the-idempotency-key-does]

`Idempotency-Key` сообщает серверу, что отправки с одним и тем же ключом — это один и тот же заказ, поэтому повторная
отправка не оформит его дважды.

1. Отправьте **Create order** ещё раз. Id в `Location` меняется: `{{$uuid}}` создал новый ключ.
2. На вкладке **Заголовки** замените `{{$uuid}}` фиксированным значением, например `tutorial-order-1`.
3. Отправьте дважды. В обоих ответах будет один и тот же id заказа.

Настоящие API используют ключ, чтобы отбросить повторный запрос, который уже был принят в первый раз. Echolot тоже его
использует: если удерживаемое открытым соединение закрывается до какого-либо ответа, он отправляет запрос повторно по
новому соединению, только если двойная отправка безвредна. Это верно для `GET`, `PUT`, `DELETE` и других безопасных или
идемпотентных методов, а также для любого запроса с заголовком `Idempotency-Key`. `POST` без него завершается ошибкой,
чтобы заказ никогда не оформлялся дважды у вас за спиной. Когда закончите, верните `{{$uuid}}`.

Ещё две вещи, которые проверяет магазин:

- Измените количество на `0` и отправьте: `422 Unprocessable Content` перечислит, что не так с каждой позицией.
- **Orders with OAuth 2** в Alpenglow получает токен по учётным данным клиента. Этим токеном можно читать заказы, но не
  оформлять их: `POST /v1/orders` с ним отвечает `403 Forbidden`.

## Дальше [#next-steps]

- [Тестирование API и запуск в CI](/docs/tutorials/test-in-ci): добавьте проверки и запустите всю цепочку целиком.
- [Скрипты и тесты](/docs/requests/scripts-and-tests): `pm.environment.set()` и родственные вызовы, когда захвата мало.
- [OAuth 2.0 и другие типы авторизации](/docs/requests/auth): пусть Echolot сам получает и обновляет токены.
