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 | Зачем |
|---|---|---|
Метод | Выпадающий список слева от адреса | Что делаем: читаем (GET), создаём (POST), меняем (PUT/PATCH), удаляем (DELETE) |
URL | Адресная строка | Куда идём — адрес ресурса |
Query-параметры | Вкладка Params | Фильтры и настройки после знака |
Заголовки | Вкладка 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 |
|---|---|---|---|
| http://localhost:3000 | https://stage.api.app | https://api.app |
| local_dev_token | stage_token | (секрет) |
Запрос остаётся один. Переключили окружение на Production — тот же запрос пошёл на боевой адрес. Переключили на Local — на локальный. Ошибиться сложнее: видно, какое окружение выбрано.

Postman различает несколько уровней переменных: глобальные (видны везде), переменные коллекции, переменные окружения и локальные внутри скриптов. Если имя совпадает, побеждает более узкий уровень — переменная окружения перекроет глобальную. Для секретов есть тип переменной secret — значение прячется звёздочками и не утекает в логи и историю.
Ловушка с секретами. Когда выгружаете окружение в файл, чтобы закоммитить его в репозиторий, токены и пароли уезжают в открытом виде. Перед коммитом значения секретов нужно очищать или хранить отдельно. В команде это правило обязательно — иначе боевой токен окажется в истории git навсегда.
Авторизация: как подставить токен
Большинство API закрыты — без авторизации они отдадут 401. Postman знает основные схемы и собирает нужные заголовки сам, на вкладке Authorization.
Тип | Как работает | Где встречается |
|---|---|---|
No Auth | Без авторизации | Публичные эндпоинты, health-check |
Bearer Token | Заголовок | 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");
});
Синтаксис проверок — это библиотека 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.

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
Теперь на каждый пуш в репозиторий поднимается тестовый стенд, 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-файл и отправить — коллега импортирует. Или работать в общем командном пространстве, где коллекция видна всем сразу и обновляется в реальном времени. Файл удобнее для хранения рядом с кодом в репозитории, общее пространство — для живой совместной работы.






