/
Блог Хекслета
/
Код
/

Postman: как тестировать и отлаживать API

Postman: как тестировать и отлаживать API

25 июня 2026 г.

10 минут
Postman: как тестировать и отлаживать API

Postman: как тестировать и отлаживать API — от первого запроса до автотестов в CI

Знакомая сцена. Бэкендер выкатил новый эндпоинт, кинул в чат: «готово, проверяй». Вы открываете терминал и пишете curl. Вставляете токен из соседней вкладки — он уже протух, идёте за новым. Снова curl, теперь с заголовком. Ответ приходит одной слипшейся строкой без переносов, читать невозможно. Через полчаса вкладок в терминале десяток, в каждой свой токен и свой урл, и вы уже не помните, какой запрос работал, а какой нет.

А на следующий день фронтендер пишет: «у меня этот эндпоинт отдаёт 422, что не так?» И вы понятия не имеете — потому что ваш рабочий curl остался где-то в истории терминала, который вы вчера закрыли.

Postman убирает этот хаос. Запросы хранятся, группируются и переиспользуются. Токены подставляются сами. Ответ показывается с подсветкой и форматированием. Проверки пишутся один раз и потом гоняются автоматически — хоть руками, хоть в CI. Это разница между «я что-то там потыкал в терминале» и «у меня есть набор запросов, который проверяет API целиком за десять секунд».

Разберём по шагам: первый запрос, коллекции, переменные окружения, автотесты и прогон в пайплайне. В конце — практика на реальном публичном API, который можно потрогать прямо сейчас.

Если хотите системно разобраться с бэкендом и API — это часть программы «Python-разработчик» на Хекслете.

Зачем Postman, если есть curl и браузер

Браузер умеет делать только GET — вбили адрес, получили ответ. POST, PUT, DELETE, кастомные заголовки, тело запроса — мимо. curl умеет всё, но каждый запрос приходится собирать заново руками, а результат хранить негде.

Postman — это графическая оболочка над теми же HTTP-запросами. Вы не пишете команду в строку, а заполняете поля: метод, адрес, заголовки, тело. Запрос сохраняется. К нему можно вернуться через месяц, поделиться с коллегой, прогнать пачкой вместе с другими. Сверху — автотесты, переменные, генерация документации и заглушки для несуществующих ещё эндпоинтов.

Задача

curl

Браузер

Postman

Быстрый GET

да

да

да

POST с телом, кастомные методы

да, вручную

нет

да, в полях

Сохранить запрос на потом

нет

нет

да

Подставлять токен автоматически

нет

нет

да

Автотесты на ответ

нет

нет

да

Прогон пачкой в CI

скриптом

нет

да, через Newman

curl никуда не уходит — он по-прежнему лучший вариант для одноразовой проверки в консоли или для скрипта на сервере. Но как только проверок становится больше одной и их нужно повторять — выгоднее Postman.

Анатомия запроса: первый GET

Любой HTTP-запрос состоит из четырёх частей: метод, адрес, заголовки и тело. В Postman каждая часть — это отдельное поле или вкладка. Разберём на примере: получим список пользователей с публичного тестового API.

Создаёте новый запрос, выбираете метод GET, в адресную строку вставляете:

GET https://reqres.in/api/users?page=2

Нажимаете Send. Внизу появляется ответ: код состояния 200 OK, время ответа, размер и тело в формате JSON с подсветкой. То, что в curl было слипшейся строкой, здесь разложено по уровням и сворачивается по блокам.

Разберём части запроса:

postman_01_anatomy.png

Часть

Где в Postman

Зачем

Метод

Выпадающий список слева от адреса

Что делаем: читаем (GET), создаём (POST), меняем (PUT/PATCH), удаляем (DELETE)

URL

Адресная строка

Куда идём — адрес ресурса

Query-параметры

Вкладка Params

Фильтры и настройки после знака ? — Postman собирает их в адрес сам

Заголовки

Вкладка Headers

Метаданные: формат, авторизация, язык

Тело

Вкладка Body

Данные, которые отправляем при POST/PUT

Параметры лучше вписывать на вкладке Params, а не руками в адрес. Postman держит адрес и таблицу параметров синхронно: добавили строку в таблицу — она появилась в URL, и наоборот. Так не теряются амперсанды и не ломается кодировка.

Методы и коды состояний — короткая шпаргалка

На собеседовании и в работе это спрашивают постоянно. Метод говорит, что мы хотим сделать. Код состояния в ответе говорит, что получилось.

Метод

Действие

Меняет данные на сервере

GET

Получить ресурс

Нет

POST

Создать новый ресурс

Да

PUT

Заменить ресурс целиком

Да

PATCH

Изменить часть ресурса

Да

DELETE

Удалить ресурс

Да

Код

Что значит

Кто виноват

2xx (200, 201, 204)

Всё хорошо, запрос обработан

3xx (301, 302)

Редирект, ресурс переехал

400

Кривой запрос, сервер не понял

Клиент

401

Не авторизован, нет или протух токен

Клиент

403

Авторизован, но прав не хватает

Клиент

404

Ресурса нет

Клиент или адрес

422

Данные дошли, но не прошли валидацию

Клиент

500

Сервер упал на обработке

Сервер

Та самая ситуация из начала статьи — фронтендер получал 422. Это не «эндпоинт сломан», а «данные дошли до сервера, но не прошли проверку»: например, поле email пустое или дата в неверном формате. В Postman это видно сразу: в теле ответа сервер обычно пишет, какое поле его не устроило.

POST с телом: создаём ресурс

Чтение — половина работы. Чаще всего проверять приходится создание и изменение. Сделаем POST: создадим пользователя.

Метод меняем на POST, адрес тот же базовый. Переходим на вкладку Body, выбираем формат raw и тип JSON. Вписываем тело:

POST https://reqres.in/api/users

{
  "name": "Никита",
  "job": "SEO"
}

В ответ приходит 201 Created — сервер создал ресурс и вернул его с присвоенным id и временной меткой. Код 201, а не 200, — это правильное поведение REST: для создания нового ресурса принято возвращать именно его.

Один нюанс с заголовками. Когда вы выбираете тип Body как JSON, Postman сам добавляет заголовок Content-Type: application/json. Если выбрать формат raw без указания типа, заголовок не появится, и сервер может не понять тело. Это частая причина загадочных 400-х: тело вроде правильное, а сервер ругается — потому что не знает, что это JSON.

Коллекции: наводим порядок

Один запрос держать в голове легко. Сорок запросов к разным эндпоинтам одного сервиса — уже нет. Коллекция — это папка с запросами. Внутри можно делать вложенные папки, описания, общие настройки авторизации.

Типичная структура коллекции для одного сервиса:

Users API (коллекция)
├── Auth
│   ├── POST Login
│   └── POST Refresh token
├── Users
│   ├── GET List users
│   ├── GET User by id
│   ├── POST Create user
│   ├── PATCH Update user
│   └── DELETE User
└── Health
    └── GET Ping

Что это даёт на практике. Запросы лежат в одном месте, а не в истории терминала. Коллекцию можно выгрузить в файл и закоммитить в репозиторий рядом с кодом — тогда любой в команде получит готовый набор проверок. На уровне коллекции настраивается авторизация один раз, и все вложенные запросы её наследуют — не нужно вставлять токен в каждый.

Коллекцию целиком запускают одной кнопкой — Postman прогонит все запросы по очереди. Это уже не ручная проверка, а мини-набор тестов, который покрывает весь сервис.

Переменные и окружения: один запрос, три стенда

У сервиса обычно несколько стендов: локальный, тестовый, боевой. Адреса разные, токены разные. Держать три копии каждого запроса — путь к ошибкам: рано или поздно отправите боевой запрос на проде, думая, что он на тесте.

Решение — переменные. Вместо адреса пишете плейсхолдер в двойных фигурных скобках:

GET {{base_url}}/api/users
Authorization: Bearer {{token}}

А значения base_url и token храните в окружении. Окружение — это набор пар «имя — значение». Делаете три окружения и переключаетесь между ними одним выпадающим списком в правом верхнем углу.

Переменная

Local

Staging

Production

base_url

http://localhost:3000

https://stage.api.app

https://api.app

token

local_dev_token

stage_token

(секрет)

Запрос остаётся один. Переключили окружение на Production — тот же запрос пошёл на боевой адрес. Переключили на Local — на локальный. Ошибиться сложнее: видно, какое окружение выбрано.

postman_02_collections.png

Postman различает несколько уровней переменных: глобальные (видны везде), переменные коллекции, переменные окружения и локальные внутри скриптов. Если имя совпадает, побеждает более узкий уровень — переменная окружения перекроет глобальную. Для секретов есть тип переменной secret — значение прячется звёздочками и не утекает в логи и историю.

Ловушка с секретами. Когда выгружаете окружение в файл, чтобы закоммитить его в репозиторий, токены и пароли уезжают в открытом виде. Перед коммитом значения секретов нужно очищать или хранить отдельно. В команде это правило обязательно — иначе боевой токен окажется в истории git навсегда.

Авторизация: как подставить токен

Большинство API закрыты — без авторизации они отдадут 401. Postman знает основные схемы и собирает нужные заголовки сам, на вкладке Authorization.

Тип

Как работает

Где встречается

No Auth

Без авторизации

Публичные эндпоинты, health-check

Bearer Token

Заголовок Authorization: Bearer {токен}

JWT, самый частый вариант сейчас

Basic Auth

Логин и пароль в заголовке (base64)

Внутренние сервисы, старые API

API Key

Ключ в заголовке или query-параметре

Сторонние сервисы: карты, погода, оплата

OAuth 2.0

Получение токена через провайдера

Вход через Google, GitHub и подобные

Удобный приём — настроить авторизацию на уровне коллекции, тип Bearer, токен взять из переменной {{token}}. Тогда каждый запрос внутри наследует её, и токен лежит в одном месте. Протух — поменяли в окружении, и все запросы снова работают. Никакого копирования по вкладкам, с которого начиналась статья.

Автотесты: проверки, которые гоняются сами

Здесь Postman перестаёт быть просто удобным curl и становится инструментом тестирования. К каждому запросу можно привязать код на JavaScript, который проверит ответ. Пишется он на вкладке Scripts (раньше называлась Tests), в секции After response.

Проверки строятся на объекте pm и функции pm.test. Самое частое — проверка кода ответа:

pm.test("Статус 200", function () {
    pm.response.to.have.status(200);
});

После каждого Send Postman выполняет этот код и показывает результат на вкладке Test Results: зелёная галочка — прошло, красный крест — упало. Несколько проверок в одном запросе:

// Код ответа
pm.test("Статус 200", function () {
    pm.response.to.have.status(200);
});

// Время ответа
pm.test("Отвечает быстрее 500 мс", function () {
    pm.expect(pm.response.responseTime).to.be.below(500);
});

// Структура тела
pm.test("В ответе есть массив data", function () {
    const body = pm.response.json();
    pm.expect(body).to.have.property("data");
    pm.expect(body.data).to.be.an("array");
});

// Конкретное значение
pm.test("Первый пользователь с email", function () {
    const body = pm.response.json();
    pm.expect(body.data[0]).to.have.property("email");
});
postman_03_tests.png

Синтаксис проверок — это библиотека Chai, привычная тем, кто писал тесты на JavaScript. pm.response.json() разбирает тело ответа в объект, дальше работаете с ним как с обычным JS.

Зачем это нужно, если ответ и так видно глазами. Глазами вы проверяете один раз. Автотест проверяет каждый раз при запуске коллекции — и ловит момент, когда сервер вдруг стал отдавать не то. Поменяли что-то на бэкенде, прогнали коллекцию, увидели три красных креста — нашли поломку до того, как её увидел пользователь.

Цепочки запросов: передаём данные между шагами

Реальные сценарии состоят из нескольких запросов подряд. Сначала логинимся и получаем токен. Потом этим токеном создаём пользователя и получаем его id. Потом по id запрашиваем данные. Каждый следующий шаг зависит от предыдущего.

Руками копировать токен и id между запросами — то самое, от чего мы уходим. Postman умеет сохранять данные из ответа в переменную прямо в скрипте. Логинимся и кладём токен в окружение:

// Скрипт After response на запросе Login
pm.test("Логин успешен", function () {
    pm.response.to.have.status(200);
});

const body = pm.response.json();
pm.environment.set("token", body.token);

Теперь переменная token в окружении обновилась. Следующий запрос, где в авторизации стоит {{token}}, подхватит свежее значение автоматически. Тот же приём с id созданного ресурса:

// Скрипт After response на запросе Create user
const body = pm.response.json();
pm.environment.set("user_id", body.id);
// А в следующем запросе адрес уже использует сохранённый id:
GET {{base_url}}/api/users/{{user_id}}

Есть и обратная сторона — скрипт Pre-request, он выполняется до отправки. В нём готовят данные: считают подпись, ставят временную метку, генерируют случайный email, чтобы создать заведомо нового пользователя:

// Pre-request: уникальный email под каждый прогон
const random = Math.floor(Math.random() * 100000);
pm.environment.set("test_email", `user_${random}@test.app`);

Собрав цепочку из логина, создания, чтения и удаления, вы получаете полный сценарий жизни ресурса. Запустили коллекцию — она прошла весь путь сама и проверила каждый шаг. Это уже полноценный интеграционный тест API.

postman_04_chaining.png

Newman: прогон коллекции в CI

Кнопка запуска внутри Postman хороша, пока проверяете руками. Но настоящая польза автотестов — когда они гоняются без человека, на каждый коммит. За это отвечает Newman — консольная версия Postman.

Newman берёт выгруженный файл коллекции и файл окружения и прогоняет всё то же самое в терминале, без интерфейса. Ставится через npm:

npm install -g newman

newman run users-api.postman_collection.json \
  --environment staging.postman_environment.json

В консоль выводится отчёт: сколько запросов прошло, сколько проверок упало, где именно. Если хоть одна проверка красная, Newman возвращает ненулевой код выхода — а это значит, что пайплайн в CI остановится и не пропустит сломанный код дальше.

Минимальный шаг в GitHub Actions выглядит так:

- name: API tests
  run: |
    npm install -g newman
    newman run users-api.postman_collection.json \
      --environment staging.postman_environment.json \
      --reporters cli,junit
postman_05_ci.png

Теперь на каждый пуш в репозиторий поднимается тестовый стенд, Newman гоняет по нему всю коллекцию, и если API повёл себя не так — сборка падает. Разработчик узнаёт о поломке через минуту после коммита, а не через неделю от пользователя. Коллекция, которую вы собирали для ручной проверки, превратилась в автоматический контроль качества бесплатно.

Mock-серверы и документация

Ещё две вещи, которые часто недооценивают.

Mock-сервер — заглушка, которая отвечает заранее заданными данными. Фронтенд начинает работу, когда бэкенда ещё нет: договорились о формате ответа, подняли мок, и фронтендер пишет интерфейс на фейковых, но правильных по структуре данных. Реальный эндпоинт появится позже — формат уже совпадёт.

Документация генерируется из коллекции автоматически. Описали запросы, добавили комментарии и примеры — Postman собирает читаемую страницу с описанием эндпоинтов, параметров и примеров ответов. Это дешевле, чем вести отдельный документ, который всё равно отстанет от реальности.

Антипаттерны: как не надо

Хардкод токенов и адресов в каждом запросе. Вписали боевой адрес и токен прямо в сорок запросов — и каждый раз при смене стенда правите сорок мест. Один промах, и тестовый запрос ушёл на прод. Всё, что меняется между стендами, должно жить в переменных окружения.

Запросы без единой проверки. «Я же вижу, что ответ правильный». Видите сейчас. Через месяц бэкенд поменяется, ответ поедет, а вы об этом не узнаете, пока не сломается на проде. Минимальная проверка статуса занимает три строки и окупается на первой же поломке.

Всё в одной плоской коллекции. Сто запросов без папок, названных «New Request», «New Request Copy», «test2». Найти нужный — отдельная задача. Папки по сущностям и понятные имена стоят пяти минут и экономят часы.

Секреты в выгруженном окружении. Выгрузили окружение с боевым токеном, закоммитили в публичный репозиторий. Токен теперь в истории git навсегда, даже если удалить файл следующим коммитом. Секреты чистят перед выгрузкой.

Игнорировать заголовок Content-Type. Отправляете JSON, но сервер отвечает 400 и непонятно почему. Потому что Postman не пометил тело как JSON, и сервер принял его за обычный текст. Проверьте, что тип тела выбран правильно.

Практика: проверяем реальный API за десять минут

Теория без рук не закрепляется. Возьмём публичный API reqres.in — он создан для тренировки и не требует регистрации. Соберём маленькую коллекцию из четырёх шагов.

Шаг 1. Создайте окружение. Одна переменная: base_url со значением https://reqres.in. Дальше во всех запросах используем {{base_url}} вместо адреса целиком.

Шаг 2. GET — список пользователей. Запрос и проверка:

GET {{base_url}}/api/users?page=2

// Scripts → After response:
pm.test("Статус 200", () => pm.response.to.have.status(200));
pm.test("Есть массив data", () => {
    pm.expect(pm.response.json().data).to.be.an("array");
});

Шаг 3. POST — создаём пользователя и сохраняем id.

POST {{base_url}}/api/users
Body (JSON):
{ "name": "Никита", "job": "SEO" }

// Scripts → After response:
pm.test("Статус 201", () => pm.response.to.have.status(201));
const body = pm.response.json();
pm.environment.set("user_id", body.id);
pm.test("Вернулся id", () => pm.expect(body.id).to.exist);

Шаг 4. DELETE — удаляем созданного и проверяем.

DELETE {{base_url}}/api/users/{{user_id}}

// Scripts → After response:
pm.test("Статус 204 — удалён без тела", () => {
    pm.response.to.have.status(204);
});

Теперь нажмите на коллекцию правой кнопкой и выберите Run. Postman прогонит все четыре запроса подряд: получит список, создаст пользователя, сохранит его id, по этому id удалит. Внизу — отчёт с галочками. Вы только что собрали интеграционный тест API, который повторяется одной кнопкой. Дальше тот же файл коллекции уходит в Newman и в CI — без единой правки.


FAQ

Postman платный?

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

Нужно ли регистрироваться?

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

Чем Postman отличается от Insomnia и других аналогов?

Insomnia, Hoppscotch, встроенный HTTP-клиент в редакторах кода решают ту же задачу — отправку и проверку запросов. Postman берёт зрелостью: автотесты, Newman для CI, мок-серверы, генерация документации в одном окне. У аналогов интерфейс легче, но возможностей меньше. Базовые принципы — методы, заголовки, тело, переменные — одинаковые везде, так что навык переносится.

Обязательно ли знать JavaScript для автотестов?

Для простых проверок — нет. Шаблоны проверки статуса и структуры ответа Postman подставляет сам, остаётся поправить значения. Базовый JavaScript пригодится для цепочек запросов и сложной логики, но начать можно без него и подучить по ходу.

Postman заменяет автотесты на бэкенде?

Нет, они про разное. Юнит-тесты в коде проверяют отдельные функции изнутри. Коллекция Postman проверяет API снаружи, как его видит клиент: тот ли код ответа, та ли структура, та ли логика на цепочке запросов. Это разные уровни, и в зрелом проекте есть оба.

Как поделиться коллекцией с коллегой?

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

Никита Вихров

2 дня назад

0

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845