JavaRush /Курси /Java Server /Зберігаємо ідентифікатор і будуємо ланцюжок запитів

Зберігаємо ідентифікатор і будуємо ланцюжок запитів

Java Server
Рівень 13 , Лекція 1
Відкрита

1. Chained requests: від «копіпасту» до сценарію

Якщо ви колись вручну копіювали id із відповіді пошуку, потім вставляли його в URL запиту «деталі», а потім випадково копіювали не той id — вітаю: ви вже знаєте, навіщо взагалі придумали chained requests. Такий ручний процес крихкий, повільний і постійно псує настрій, як зависла IDE під час збереження файлу (усі ми через це проходили).

Chained request — це коли Postman допомагає вам зробити «естафету даних»: перший запит отримує відповідь, невеликий скрипт витягує потрібне значення (зазвичай ідентифікатор), зберігає його в активному середовищі, а другий запит підхоплює його через {{змінна}}. У підсумку ви отримуєте не «набір окремих запитів», а відтворюваний сценарій. І це прямо готує вас до майбутньої клієнтської частини проєкту ReadLater Starter, де буде такий самий потік: catalog searchcatalog details.

Де шукати id у JSON

Перед тим як писати бодай один рядок скрипта, важливо зробити крок, який багатьом здається нудним, але потім заощаджує години: уважно подивитися на форму JSON і зрозуміти, де саме лежить ідентифікатор. Postman тут не магічний — він не вгадує, що саме ви мали на увазі. Якщо ви самі не знаєте шлях до поля, скрипт теж цього «не знає» і чесно збереже undefined, а далі ви дивитиметеся на URL на кшталт /books/ і думатимете, що сервер «зламався».

Уявімо спрощену відповідь пошуку (це не про конкретного провайдера, а про типовий формат):

{
  "items": [
    { "id": "BK-101", "title": "Clean Code" },
    { "id": "BK-102", "title": "Clean Architecture" }
  ],
  "count": 2
}

Тут нас цікавить не весь об’єкт книги, не title (він може повторюватися) і навіть не count (він корисний, але не для деталей). Нас цікавить шлях items[0].id, тобто «id першого елемента списку». У реальному API поле може називатися key, externalId, bookId, а може лежати глибше, наприклад items[0].book.id. Тому перший принцип chained requests звучить просто: спочатку знайдіть поле очима, потім автоматизуйте.

Корисна звичка: подумки проговорити шлях до поля словами. Наприклад: «У кореневому об’єкті є масив items, у ньому перший елемент, а в нього поле id». Коли ви так умієте читати JSON, chained requests стають механікою, а не шаманством.

Вкладка Tests: місце для скрипта

Коли ви бачите вкладку Tests, легко вирішити, що вона потрібна лише для автотестів, а ми ж «просто дивимося відповіді». Насправді Tests у Postman — це просто місце, де ви можете виконати невеликий JavaScript-код після того, як відповідь уже отримано. І це ідеальний момент, щоб дістати дані з відповіді та зберегти їх у змінну середовища.

Логіка проста. До запиту ви не знаєте, який id повернеться. Після запиту — знаєте, бо він уже в response body. Тому ми діємо так: відправили Search → отримали JSON → у Tests скрипт прочитав JSON → скрипт зберіг bookId → далі Details використовує {{bookId}}.

Об’єкт pm — це вбудований API Postman усередині скрипта. Він дає вам доступ до відповіді (pm.response), до середовища (pm.environment), до логів (console.log) і до простих перевірок. Вам не потрібно ставати JavaScript-розробником. Ми використовуємо рівно дві-три функції, ніби беремо в руки маленьку викрутку, а не будуємо завод із виробництва викруток.

2. Мінімальний скрипт у Tests

Зараз буде ключовий момент лекції, але він набагато простіший, ніж здається. Нам потрібно виконати дві операції: перетворити body відповіді на об’єкт і зберегти з нього одне значення в середовище. Для цього в Postman є два майже самозрозумілі інструменти: pm.response.json() і pm.environment.set().

Почнімо з найпростішого «скелета» логіки. На вкладці Tests у вашому запиті пошуку пишемо:

// Парсимо JSON-відповідь (body) в об’єкт, з яким можна працювати як зі звичайним JS-об’єктом
const body = pm.response.json();

// Перевіряємо, що поле items існує і що там справді є хоча б один елемент
if (body.items && body.items.length > 0) {
  // Беремо id першого елемента результатів (перевірте шлях за реальним JSON вашого API)
  const firstBookId = body.items[0].id;

  // Зберігаємо значення в активному середовищі, щоб наступний запит міг використовувати {{bookId}}
  pm.environment.set("bookId", firstBookId);

  // Лог у Postman Console допомагає швидко побачити, що саме збереглося
  console.log("Збережено bookId =", firstBookId); // Збережено bookId = BK-101
}

Сенс рядків буквально такий.

pm.response.json() бере текст body і парсить його як JSON. Якщо відповідь не JSON або JSON пошкоджений, Postman не зможе його розпарсити — і це корисний сигнал: або запит не туди, або сервер повернув HTML-сторінку помилки, або не той Content-Type.

Далі ми робимо перевірку, що items взагалі є і що він не порожній. І лише тоді зберігаємо bookId. Зверніть увагу: ми зберігаємо одне конкретне поле, а не всю відповідь. У chained requests цінність не в тому, щоб «запам’ятати все», а в тому, щоб акуратно перенести мінімально потрібний шматок даних у наступний крок.

І маленький побутовий лайфхак: console.log можна дивитися в Postman Console. Це як «логування» для Postman-сценарію. Дуже допомагає, коли ви налагоджуєте шлях до поля або намагаєтеся зрозуміти, чому змінна не зберігається.

3. {{bookId}} у запиті деталей: підхоплення змінної

Після того як пошук зберіг bookId, другий запит із деталями має перестати бути «запитом із ручною вставкою». Він стає шаблоном. І саме це робить вашу колекцію по-справжньому переносною: один і той самий запит можна запускати сьогодні, завтра і через тиждень — без «ритуалу копіювання».

URL запиту деталей зазвичай має такий вигляд:

# Запит деталей книги за раніше збереженим bookId
GET {{baseUrl}}/books/{{bookId}}

Тут {{baseUrl}} ви вже винесли в середовище в попередній лекції. А {{bookId}} ми тепер не вводимо вручну — він з’являється автоматично після виконання пошуку.

Важливий момент для розуміння: Postman підставляє змінні в момент надсилання запиту. Якщо змінна не задана, Postman не «вгадає» значення, він чесно залишить {{bookId}} як текст або підставить порожнечу — залежно від ситуації. Тому, якщо ви бачите дивний URL, насамперед перевірте активне середовище і чи справді в ньому збережено bookId.

Так ви отримуєте ланцюжок, який майже схожий на невеликий backend-потік: спочатку знайти книгу за запитом, потім за знайденим ідентифікатором запросити деталі.

4. Ланцюжок і порожній результат пошуку

Тут важливо не переплутати: повноцінні negative-path сценарії ми розбиратимемо окремо, але ланцюжок запитів має принаймні не валитися, якщо пошук нічого не знайшов. У реальності таке трапляється постійно. Не тому, що API погане, а тому, що користувачі — і ви також — вводитимуть різні запити: з помилками, з рідкісними словами, із порожнім рядком.

Найчастіша проблема ланцюжків звучить так: пошук повернув порожній список, bookId не зберігся, а запит деталей усе одно відправили, і він пішов «за деталями за відсутнім id». У кращому разі ви отримаєте 404, у гіршому — неочевидну помилку. Тому нам потрібна мінімальна дисципліна: якщо нічого зберігати, ми явно це показуємо.

Можна трохи розширити скрипт і додати зрозумілий сигнал:

// Парсимо відповідь пошуку
const body = pm.response.json();

// Якщо items немає або він порожній — нічого не зберігаємо, а залишаємо явний слід у логах
if (!body.items || body.items.length === 0) {
  console.log("Пошук повернув 0 елементів. bookId не встановлено."); // підказка в консоль
} else {
  // Інакше беремо id першого результату і зберігаємо його в середовищі
  const firstBookId = body.items[0].id;

  pm.environment.set("bookId", firstBookId);
  console.log("Збережено bookId =", firstBookId); // Збережено bookId = BK-101
}

Це все ще проста логіка, без «тест-фреймворків». Ви просто робите поведінку ланцюжка передбачуваною. Якщо хочете трохи суворіше, можна додати перевірку, яка підсвітить проблему прямо у звіті запиту:

// Парсимо JSON, щоб використати його в перевірці
const body = pm.response.json();

// Невеликий тест: якщо результатів немає, ми явно "падаємо" і зупиняємо ланцюжок на цьому кроці
pm.test("Пошук повернув щонайменше один елемент", () => {
  if (!body.items || body.items.length === 0) {
    // Помилку буде видно в результатах запиту, а не лише в консолі
    throw new Error("Нічого не знайдено, неможливо побудувати ланцюжок до деталей");
  }
});

Якщо ви поки не хочете звикати до pm.test, це нормально. Але сама ідея важлива: ланцюжковий сценарій має бути чесним і не вдавати, що дані завжди є.

5. Схема chained-сценарію

Коли ви вперше робите chained requests, усе відчувається так, ніби Postman щось чаклує. Щоб зняти цю магію, корисно уявити потік у вигляді дуже простої схеми. У вас є лише три елементи: запит пошуку, активне середовище, яке працює як маленька кишеня для змінних, і запит деталей.

sequenceDiagram
    participant P as Postman
    participant API as API каталогу
    participant ENV as Активне середовище

    P->>API: "GET {{baseUrl}}/search?q={{searchQuery}}&limit={{limit}}"
    API-->>P: "200 + JSON (items[])"
    P->>ENV: "зберегти bookId = items[0].id (Tests)"
    P->>API: "GET {{baseUrl}}/books/{{bookId}}"
    API-->>P: "200 + JSON (деталі)"

Сенс діаграми в одному: ENV — це передавальна ланка. Ми не переносимо дані вручну. Ми передаємо їх через змінну, яку один запит записав, а інший прочитав.

Якщо ви тримаєте це в голові, ви перестаєте боятися chained requests. Там немає таємної магії: лише «прочитав JSON → поклав значення → підставив значення».

6. Гігієна змінних у Postman

Коли змінних стає більше двох, починається типова хаотичність новачка: змінна називається id, але яка саме? Книги? Автора? Запиту? А ще вчора була book_id, а сьогодні bookId, і все це в різних запитах. Щоб колекція залишалася зрозумілою, до змінних варто ставитися як до частини контракту вашої Postman-колекції.

Найпростіше правило — ім’я змінної має відповідати на запитання «що це?». Тому bookId набагато краще, ніж id. baseUrl краще, ніж url. searchQuery краще, ніж q. Це не «естетика», це економія мозку: ви відкриваєте колекцію через тиждень і не починаєте розслідування рівня детектива, хто такий id.

Ще один нюанс: значення змінних середовища в Postman по суті є рядками. Навіть якщо limit виглядає як число, найчастіше він зберігається як "3". Це нормально, бо в URL усе одно йде текст. Просто не дивуйтеся, що десь значення виглядає «як рядок». У межах Postman-шаблонів це очікувано.

Зручно тримати в себе невелику таблицю-орієнтир:

Змінна Приклад значення Хто задає Хто використовує
baseUrl https://catalog.example.com вручну в середовищі усі запити
searchQuery clean code вручну в середовищі запит пошуку
limit 3 вручну в середовищі запит пошуку
bookId BK-101 скрипт у Tests для запиту пошуку запит деталей

І ще одне вічне джерело помилок: активне середовище. Змінна може бути записана в середовище, але якщо середовище не вибрано як активне або ви перемкнулися на інше, ви дивитиметеся на {{bookId}} як на порожнечу. Тому звичка проста: перед запуском сценарію ви перевіряєте, яке середовище зараз активне, як водій перевіряє, яка передача ввімкнена в машині. Інакше потім буде запитання: «Чому все поїхало не туди?»

7. Як це пов’язано з ReadLater Starter

На цьому етапі курсу Postman — це ваша лабораторія, де ви фіксуєте контракт до того, як почнете писати Java-код. І chained requests — це спосіб перетворити контракт із «двох окремих прикладів» на сценарій, який нагадує реальну взаємодію сервісів. Сьогодні ви будуєте ланцюжок search → details вручну, а пізніше те саме відбуватиметься в коді: застосунок спочатку шукає книги, потім за вибраним ідентифікатором запитує детальну картку.

Це важливо ще й психологічно. Коли ви писатимете Java HTTP-клієнт, у вас уже буде зрозуміла модель: який запит перший, які параметри в ньому беруть участь, яке поле з відповіді потрібно взяти і який запит іде другим. Ви не будете «вигадувати API на дотик» просто в коді. А код, який пишеться за чітким контрактом, зазвичай ламається рідше й налагоджується швидше (і так, це прямо впливає на кількість нервових зітхань на день).

8. Типові помилки під час chained requests у Postman

Коли починаєте пов’язувати запити, помилки стають трохи хитрішими, бо проблема може бути не в конкретному запиті, а в тому, що ланцюжок не передав дані. Це нормально: ви саме вчитеся бачити сценарій цілком. Нижче — найчастіші граблі, на які наступають майже всі (і я теж, просто наступав на них раніше, щоб вам було простіше).

Помилка №1: зберігають не одне поле, а всю відповідь цілком.
Іноді здається логічним «зберегти JSON у змінну», а потім «якось дістати з неї id». На практиці це швидко перетворюється на величезний рядок, який незручно читати, незручно переносити й легко випадково зламати. Ланцюжок має передавати мінімально потрібне значення. Для details потрібен bookId, отже зберігаємо bookId, а не весь всесвіт.

Помилка №2: плутають шлях до поля в JSON (і зберігають undefined).
Найтиповіший сценарій: ви пишете body.items[0].id, а насправді поле називається key або масив називається docs. Postman чесно збереже undefined, а ви далі отримаєте URL без id. Лікується це нудно, але надійно: один раз уважно подивитися на реальний JSON, знайти поле і лише потім писати скрипт. Якщо сумніваєтеся, тимчасово виведіть console.log(body) і подивіться на структуру.

Помилка №3: не перевіряють, що масив не порожній.
Якщо пошук повернув порожній список, звернення до items[0] дасть вам undefined, і далі ви збережете «порожнечу». Це не «рідкісний corner case», а реальний сценарій. Мінімальний захист через if (items.length > 0) робить ланцюжок передбачуваним. Навіть якщо ви поки не робите повноцінний negative-path набір, ланцюжок має поводитися акуратно.

Помилка №4: використовують надто загальне ім’я змінної (id).
Змінна id живе рівно до моменту, коли ви додасте другий id іншого типу. Після цього починаються дивні ефекти: ви думаєте, що зберігаєте id книги, а насправді там лежить id автора з іншого запиту, бо ви повторно використали ім’я. Хороша колекція читається як текст: bookId, searchQuery, baseUrl. Так, це трохи довше, зате мозок не перегрівається.

Помилка №5: забувають, що потрібно вибрати активне середовище.
Скрипт може ідеально виконуватися, але якщо ви запускаєте запит без вибраного середовища або з іншим середовищем, змінна зберігатиметься не туди (або взагалі не буде видна). І ви отримаєте відчуття, що Postman «глючить». На практиці це майже завжди не глюк, а просто неправильне активне середовище. Звичка: перед натисканням Send дивимося на розкривний список середовищ.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ