Проверить сервер напрямую — без интерфейса, который прячет и ограничивает запросы
API (application programming interface) — способ, которым программы обращаются к серверу без человека: мобильное приложение, сайт на JavaScript, другие сервисы. У «Задачника» есть и веб-интерфейс, и JSON API по адресам /api/….
Через API тестировщик проверяет сервер напрямую. Интерфейс ограничивает запросы: не даёт ввести приоритет 0, не показывает кнопку запрещённого перехода, не позволяет отправить поле другого типа. API этих ограничений не имеет — и злоумышленник тоже пользуется им напрямую. Поэтому проверки API находят дефекты, которые через интерфейс не видны вовсе, а проверка в разделе 08 «обойти клиентскую проверку» здесь становится обычным запросом.
Каждое обращение к API — пара «запрос — ответ»:
POST /api/login HTTP/1.1 ← метод, адрес, версия протокола
Host: 127.0.0.1:8000 ← заголовки
Content-Type: application/json
{"login": "ivan", "password": "Ivan2026pass"} ← тело
HTTP/1.0 200 OK ← код состояния
Content-Type: application/json; charset=utf-8
{"token": "…"} ← тело ответа
| Метод | Что делает | Пример |
|---|---|---|
GET | Получить, ничего не меняя | GET /api/tasks — список задач |
POST | Создать или выполнить действие | POST /api/tasks — новая задача |
PATCH | Изменить часть полей | PATCH /api/tasks/5 — новое название |
PUT | Заменить целиком | в «Задачнике» нет |
DELETE | Удалить | DELETE /api/tasks/5 |
Стиль, где адрес называет объект (/api/tasks/5 — задача 5), а метод — действие с ним, называют REST. Ответы обычно в JSON: объекты {"ключ": значение}, массивы […], строки в двойных кавычках, числа, true/false, null.
Код состояния — первое, что проверяют:
| Код | Значит | Когда |
|---|---|---|
| 200 OK | Успешно | Получили, изменили |
| 201 Created | Создано | После POST, создавшего объект |
| 204 No Content | Успешно, тела нет | Удалили, вышли |
| 400 Bad Request | Ошибка в запросе | Неверное поле, неверный JSON |
| 401 Unauthorized | Не авторизован | Нет токена или он недействителен |
| 403 Forbidden | Авторизован, но нельзя | Чужой объект, нет прав |
| 404 Not Found | Нет такого | Неверный адрес или id |
| 409 Conflict | Противоречит состоянию | Запрещённый переход статуса, дубликат |
| 500 Internal Server Error | Сервер упал | Всегда дефект: сервер должен был ответить 4xx |
Коды 4xx — «виноват клиент», и это нормальный ответ на негативную проверку. Код 5xx — «виноват сервер»: необработанная ошибка, которую нужно исправлять.
OpenAPI (раньше Swagger) — стандартный формат описания API: адреса, методы, поля запроса, коды и поля ответов. Для тестировщика это требования к API (Т8.1). Описание «Задачника» — http://127.0.0.1:8000/api/openapi.json; откройте в браузере — Edge и Chrome покажут его с отступами. Начало файла:
{
"openapi": "3.1.0",
"info": {
"title": "Задачник API",
"version": "1.0"
},
"servers": [
{
"url": "http://127.0.0.1:8000"
}
],
"components": {
Что выписать из документации для проверок:
paths — адреса и методы; у каждого — summary (что делает).requestBody — какие поля обязательны (required), их типы и ограничения (minLength, maximum, enum).responses — какие коды бывают и что в ответе. Код, которого нет в документации, или другой код для той же ситуации — расхождение, о нём пишут баг-репорт: «по OpenAPI — 201, получено — …».security — нужна ли авторизация и какая.Bruno умеет импортировать OpenAPI и сразу создать коллекцию со всеми адресами. В этом разделе мы собираем коллекцию вручную — так лучше видно, что проверяется.
curl есть в Windows 10 и 11 и почти в любом Linux. Основные ключи: -i — показать код и заголовки ответа, -X — метод, -H — заголовок, --json — отправить JSON (сам ставит Content-Type).
curl в PowerShell 5.1 — не curl, а другая команда (Invoke-WebRequest); пишите curl.exe. 2) JSON в кавычках прямо в команде PowerShell 5.1 передаёт программе без внутренних кавычек, и сервер получает сломанное тело — в «Задачнике» это видно как ошибка сервера. Надёжный способ — положить JSON в файл и отправлять --json "@файл.json". В cmd и Linux такой проблемы нет.Запрос без токена (PowerShell, Windows 11):
PS C:\tasker> curl.exe -i http://127.0.0.1:8000/api/tasks
HTTP/1.0 401 Unauthorized
Server: Tasker
Date: Thu, 29 Oct 2026 10:07:53 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 99
{
"error": "Требуется вход: заголовок Authorization: Bearer <токен>"
}
Вход: создайте в папке «Задачника» файл login.json (Блокнот, кодировка UTF-8) с текстом {"login": "ivan", "password": "Ivan2026pass"} и отправьте его:
PS C:\tasker> curl.exe --json "@login.json" http://127.0.0.1:8000/api/login
{
"token": "38e22c9c78a9fd5ed9e5cf6a51da6a01"
}
Токен у вас будет другой. Сохраните его в переменной и передавайте в заголовке Authorization:
PS C:\tasker> $token = "38e22c9c78a9fd5ed9e5cf6a51da6a01"
PS C:\tasker> curl.exe -H "Authorization: Bearer $token" "http://127.0.0.1:8000/api/tasks?status=in_progress"
[
{
"id": 1,
"title": "Подготовить отчёт за квартал",
"due": "2026-10-27",
"priority": 1,
"status": "in_progress",
"overdue": true,
"created": "2026-10-29 13:07:50",
"updated": "2026-10-29 13:07:50"
},
…
]
Несуществующая задача — 404 и ошибка в JSON:
PS C:\tasker> curl.exe -i -H "Authorization: Bearer $token" http://127.0.0.1:8000/api/tasks/9999
HTTP/1.0 404 Not Found
Server: Tasker
Date: Thu, 29 Oct 2026 10:07:54 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 49
{
"error": "Задача не найдена"
}
Те же запросы в Linux (bash) — JSON можно писать прямо в команде, в одинарных кавычках:
curl -i http://127.0.0.1:8000/api/tasks
curl --json '{"login": "ivan", "password": "Ivan2026pass"}' http://127.0.0.1:8000/api/login
TOKEN=38e22c9c78a9fd5ed9e5cf6a51da6a01
curl -H "Authorization: Bearer $TOKEN" 'http://127.0.0.1:8000/api/tasks?status=in_progress'
curl -X PATCH -H "Authorization: Bearer $TOKEN" --json '{"title": "Новое"}' http://127.0.0.1:8000/api/tasks/3
Если curl старый и отвечает, что не знает ключ --json: -H "Content-Type: application/json" -d "@login.json". Кириллица в ответах в окне терминала Windows 11 показывается правильно; если передать вывод curl дальше командам PowerShell (| ConvertFrom-Json, > файл), буквы могут исказиться — сохраняйте ответ ключом -o ответ.json.
curl удобен для одного запроса, а для набора проверок, которые нужно повторять, удобнее Bruno. Он хранит коллекцию файлами в папке на диске — её можно положить в git и отдать одногруппнику. Учётная запись не нужна. Postman делает то же, но требует учётную запись и хранит коллекции в облаке.
Как собрать коллекцию «Задачника»:
local с переменной base = http://127.0.0.1:8000. Адреса запросов пишутся как {{base}}/api/login — для другого сервера достаточно другого окружения.{{base}}/api/login, вкладка Body → JSON, тело с логином и паролем. Отправить — кнопка Send или Ctrl+Enter.token со значением res.body.token. Теперь после входа токен запоминается сам.{{token}}.Слева — коллекция, в середине — запрос (метод, адрес, тело), справа — ответ с кодом, временем и размером. Второй запрос — список задач в работе — берёт токен из переменной:
Чтобы не сверять ответ глазами каждый раз, ожидаемый результат записывают проверкой на вкладке Tests запроса — небольшим кодом на JavaScript. Программировать для этого почти не нужно, достаточно образца:
test("200 и только задачи в работе", function () {
expect(res.getStatus()).to.equal(200);
res.getBody().forEach(t => expect(t.status).to.equal("in_progress"));
});
После отправки результат — на вкладке Tests ответа (может прятаться под »): зелёная галочка — проверка прошла, красный крестик — нет, с объяснением «expected 200 to equal 201».
| Что проверить | Строка в test(…) |
|---|---|
| Код ответа | expect(res.getStatus()).to.equal(201); |
| Поле ответа | expect(res.getBody().priority).to.equal(2); |
| Поле есть и это строка | expect(res.getBody().error).to.be.a("string"); |
| Длина списка | expect(res.getBody()).to.have.lengthOf(8); |
| Заголовок | expect(res.getHeader("content-type")).to.contain("application/json"); |
Запуск всей коллекции: правой кнопкой по коллекции → Run. Bruno пройдёт запросы по порядку и покажет, какие проверки не прошли, — это уже почти регрессионный набор API, и в курсе автоматизации его запускают без интерфейса.
Техники разделов 05–06 работают и для API — только вместо полей формы поля JSON. Для каждого адреса:
| Группа | Проверки | Ожидается |
|---|---|---|
| Позитивные | Каждый метод из OpenAPI с корректными данными; поля ответа совпадают с отправленными | Код из документации, поля по схеме |
| Обязательные поля | Поле пропущено; null; пустая строка | 400 и понятная ошибка |
| Типы | Число строкой "3", строка вместо числа, true, массив, объект | 400 |
| Границы | Те же, что в разделе 05: длины, диапазоны, даты | Как в требованиях |
| Лишнее | Неизвестное поле "owner": "maria", "id": 1 | Игнорируется или 400, но не меняет данные |
| Формат | Сломанный JSON {title:; пустое тело; другой Content-Type | 400, не 500 |
| Состояния | Запрещённые переходы из таблицы раздела 06, которых нет в интерфейсе | 409 |
| Адрес и метод | Несуществующий id; id строкой /api/tasks/abc; неподдерживаемый метод | 404, 405 |
| Авторизация | Без токена; неверный токен; токен после выхода | 401 на каждом адресе, где он нужен |
| Чужие данные | Токен одного пользователя, id объекта другого | 404 или 403; данные не показаны и не изменены |
Авторизацию проверяют на каждом адресе из документации, а не на одном: разработчик мог забыть проверку токена в одном обработчике.
Один из самых частых и опасных дефектов API: сервер проверяет, что пользователь вошёл, но не проверяет, что объект — его. Подставив в адрес чужой номер, пользователь видит или меняет чужие данные. В классификации OWASP это первое место списка API Security Top 10 (BOLA — broken object level authorization).
Как проверять в учебном приложении:
GET, PATCH, DELETE и смену статуса для id задачи второго пользователя.Для дефекта API шаги — это запрос. В баг-репорт вставляют команду curl целиком (без настоящих паролей рабочих систем) или команду, которую Bruno собирает сам (значок </> справа от адреса запроса, вариант curl), фактический ответ с кодом и ожидаемый — со ссылкой на OpenAPI:
API: GET /api/orders/{id} с id несуществующего заказа отвечает 500 вместо 404
Окружение: «Магазин» 2.3 API, test.example.ru; curl 8.21
Требование: OpenAPI, /api/orders/{id} → responses 404
Шаги:
curl.exe -i -H "Authorization: Bearer <токен test01>" https://test.example.ru/api/orders/999999
Фактический результат: HTTP 500, тело «Internal Server Error» (не JSON)
Ожидаемый результат: HTTP 404, {"error": "…"}
curl.exe и JSON из файла --json "@файл.json"{{base}}, токен в переменной, проверки на вкладке Tests, запуск всей коллекции