Если на невалидный ввод приходит 500, это баг: сервер должен вернуть 4xx, а не падать. Без проверки 403 работает обход авторизации: если обычный пользователь обращается к admin-эндпоинту и получает 200 вместо 403, контроль доступа не работает. В этом гайде: все статус-коды которые встретятся в API-тестах, что каждый из них должен и не должен возвращать, и примеры Playwright для проверки статус-кодов на эндпоинтах аутентификации, валидации и создания ресурсов.
Как организованы статус-коды
Все HTTP статус-коды делятся на пять классов:
| Диапазон | Класс | Значение |
|----------|-------|---------|
| 1xx | Информационные | Запрос получен, обработка продолжается |
| 2xx | Успех | Запрос выполнен успешно |
| 3xx | Перенаправление | Клиент должен выполнить дополнительное действие (обычно перейти по редиректу) |
| 4xx | Ошибка клиента | Проблема в запросе: клиент прислал что-то неверное |
| 5xx | Ошибка сервера | Запрос был валидным: сервер не смог его выполнить |
Первая цифра говорит о категории. 4xx: запрос был плохим. 5xx: сервер сломался.
2xx: коды успеха
200 OK
Самый частый код успеха. Запрос сработал, в ответе есть контент.
Используется для GET-запросов возвращающих данные, POST-запросов которые не создают новый ресурс (например поиск) и обновлений PUT/PATCH.
В тестах проверяй что тело ответа содержит ожидаемые данные, что ответ в правильном формате (JSON, XML) и что обязательные поля присутствуют.
201 Created
Ресурс успешно создан. Должен возвращаться для POST-запросов создающих новые элементы.
В тестах проверяй что ответ включает созданный ресурс с новым ID, что заголовок Location часто указывает на URL нового ресурса, и что вызов POST /users возвращает 201 с { id: 123, email: "...", ... }.
200 вместо 201 для эндпоинтов создания. Технически работает, но семантически неверно и может путать потребителей.
204 No Content
Успех, но нечего возвращать. Используется для DELETE-запросов и некоторых ответов PUT/PATCH.
В тестах проверяй что тело ответа пустое (некоторые API ошибочно возвращают тело с 204) и что ресурс реально удалён (проверь последующим GET-запросом).
206 Partial Content
Возвращается когда отправляется только часть ресурса (чанкованные загрузки, потоковое видео). Актуален при тестировании загрузки файлов и медиастриминга.
3xx: коды перенаправления
301 Moved Permanently
Ресурс навсегда переехал на новый URL. Поисковые системы обновляют свои индексы при 301.
Актуальность для тестирования: проверяй что старые URL правильно перенаправляют, что HTTPS-редиректы с HTTP возвращают 301 (а не 302), и что адресаты редиректов корректно загружаются.302 Found (временный редирект)
Ресурс временно находится по другому URL. Используется для редиректов после логина («иди сюда сейчас, исходный URL всё ещё действителен»).
304 Not Modified
У клиента есть кэшированная версия и она актуальна. Контент не отправляется, используй кэш. Видишь во вкладке Network браузера для статических ресурсов.
Актуальность для тестирования: если тестируешь кэширование, 304 означает что кэш работает. Если видишь 304 для данных которые должны были измениться, это баг кэширования.4xx: коды ошибок клиента
Означают что проблема в запросе: плохие данные, отсутствие авторизации, неверный URL.
400 Bad Request
Сервер не смог понять запрос. Обычно означает неверный синтаксис, невалидный JSON или ошибку валидации.
400 должен появляться при невалидном JSON в теле запроса, отсутствующем обязательном заголовке или некорректном URL.
В тестах проверяй что ответ возвращает полезное сообщение об ошибке объясняющее проблему, не раскрывает внутренние детали (стек-трейсы) и возвращает 400, а не 500. Если на плохой ввод приходит 500, это баг сервера.
401 Unauthorized
В запросе отсутствуют корректные учётные данные. «Ты не залогинен» или «твой токен истёк».
Разница с 403: 401 означает не аутентифицирован (кто ты?). 403 означает аутентифицирован, но нет прав (я знаю кто ты, просто это тебе недоступно).Что тестировать
- Запрос без токена → 401
- Запрос с истёкшим токеном → 401
- Запрос с невалидным или поддельным токеном → 401
- Ответ с ошибкой не раскрывает информацию о валидных токенах
403 Forbidden
Аутентифицирован, но не разрешено. «Ты залогинен, но у тебя нет прав на это».
В тестах проверяй что обычный пользователь обращаясь к admin-эндпоинту получает 403, что попытка получить приватные данные другого пользователя возвращает 403, и что ответ не раскрывает данные которые пользователь не должен видеть.
Актуальность для безопасности: отсутствующая проверка 403 означает что несанкционированный доступ работает. Настоящий баг безопасности.404 Not Found
Запрошенный ресурс не существует по этому URL.
Что тестировать
- Запрос удалённого ресурса → 404
- Запрос с ID который никогда не создавался → 404
- Для чувствительных ресурсов не раскрывать факт существования (аккаунт пользователя: возврат 404 «пользователь не найден» против 403 «запрещено» может раскрыть существование аккаунта)
- Это 404 или 410? (410 означает удалён навсегда; некоторые API их различают)
405 Method Not Allowed
Использован неверный HTTP-метод. GET на эндпоинте который принимает только POST.
DELETE /users когда должен быть только GET. Должен вернуть 405, а не 500 или молчаливый сбой.
409 Conflict
Запрос конфликтует с текущим состоянием ресурса.
Частые случаи: создание пользователя с email который уже существует, редактирование ресурса который заблокирован другим пользователем, конфликт версий (оптимистичная блокировка).
В тестах проверяй что создание дубликата возвращает 409 (не 200 и не 500), а ответ чётко объясняет конфликт.
422 Unprocessable Entity
Запрос был синтаксически корректным JSON, но семантически неверным: валидация не прошла.
Пример: валидное тело JSON, ноage: -5 нарушает правило что возраст должен быть положительным.
400 vs 422: 400 означает что не удалось разобрать запрос (плохой JSON, неверный Content-Type), 422 означает что разобрался нормально, но значения не прошли валидацию.
Многие API используют 400 для обоих случаев. Важна последовательность: выбери один вариант и используй его корректно по всему API.
В тестах проверяй что отсутствие каждого обязательного поля даёт 422 с конкретным именем поля в ошибке, что значения поля вне допустимого диапазона возвращают 422, и что нарушения бизнес-правил возвращают 422.
429 Too Many Requests
Rate limiting: слишком много запросов за слишком короткое время.
В тестах подтверждай что возвращаются заголовки rate limit (X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After), что после достижения лимита запросы отклоняются, и что после истечения окна запросы снова работают.
5xx: коды ошибок сервера
Всегда баги. Запрос был валидным, а сервер не смог его обработать.
500 Internal Server Error
Общий сбой сервера. Произошло что-то неожиданное.
При тестировании: если можешь воспроизвести 500 стабильно, это баг, даже если ввод был намеренно плохим. Хороший API-дизайн означает что невалидный ввод возвращает 4xx, а не 500.В тестах проверяй что невалидный ввод не даёт 500 (должен давать 400/422), что null или отсутствующие необязательные поля не дают 500, и что граничные данные (пустые массивы, очень длинные строки) не дают 500.
502 Bad Gateway
Сервер действовал как шлюз или прокси и получил плохой ответ от вышестоящего сервера. Часто означает что зависимость недоступна.
503 Service Unavailable
Сервер временно недоступен: перегружен или на техническом обслуживании.
Актуальность для тестирования: проверяй как фронтенд обрабатывает 503. Показывает ли понятную страницу ошибки? Делает ли умные повторные попытки? Деградирует ли корректно?504 Gateway Timeout
Похоже на 502: шлюз ждал слишком долго ответа от вышестоящего сервера. Часто появляется при высокой нагрузке или когда сторонний сервис тормозит.
Таблица быстрого справочника
| Код | Значение | Частая причина в багах |
|-----|---------|----------------------|
| 200 | OK | Возвращается для создания вместо 201 |
| 201 | Created | Отсутствует: API возвращает 200 для POST |
| 204 | No Content | Тело возвращается когда не должно |
| 301 | Permanent Redirect | Неверный тип редиректа |
| 304 | Not Modified | Устаревший кэш показывает старые данные |
| 400 | Bad Request | Возвращается для валидного-но-неверного ввода (должен быть 422) |
| 401 | Unauthorized | Отсутствует: уязвимость обхода аутентификации |
| 403 | Forbidden | Отсутствует: уязвимость обхода авторизации |
| 404 | Not Found | 500 возвращается для отсутствующих ресурсов |
| 409 | Conflict | Отсутствует: дубликаты создаются молча |
| 422 | Unprocessable Entity | Путают с 400 |
| 429 | Too Many Requests | Отсутствует: возможен брутфорс |
| 500 | Internal Server Error | Вызывается невалидным вводом (должен быть 4xx) |
| 503 | Service Unavailable | Нет корректной деградации на фронтенде |
Тестирование статус-кодов в Playwright
test('создание пользователя возвращает 201', async ({ request }) => {
const response = await request.post('/api/users', {
data: { email: 'new@test.com', password: 'ValidPass1' },
});
expect(response.status()).toBe(201);
});
test('дублирующийся email возвращает 409', async ({ request }) => {
// Сначала создаём пользователя
await request.post('/api/users', {
data: { email: 'existing@test.com', password: 'ValidPass1' },
});
// Пробуем снова с тем же email
const response = await request.post('/api/users', {
data: { email: 'existing@test.com', password: 'ValidPass1' },
});
expect(response.status()).toBe(409);
});
test('отсутствующий токен возвращает 401', async ({ request }) => {
const response = await request.get('/api/profile');
expect(response.status()).toBe(401);
});
test('неверная роль возвращает 403', async ({ request }) => {
// Используем токен обычного пользователя, обращаемся к admin-эндпоинту
const response = await request.get('/api/admin/users', {
headers: { Authorization: `Bearer ${memberToken}` },
});
expect(response.status()).toBe(403);
});Тесты на статус-коды выполняются за миллисекунды и ловят баги авторизации, отсутствующую валидацию и некорректный API-дизайн. Писать их быстро, и они работают надёжно.
→ See also: API-тестирование 101: всё, что нужно знать QA-инженеру в 2026 году | Что такое REST API? Практическое руководство для QA-инженеров | API-тестирование в Playwright: выходим за рамки UI | Авторизация в API-тестах: API-ключи, Bearer-токены, OAuth2, JWT