Если на невалидный ввод приходит 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: "...", ... }.

Частый баг для поиска: API возвращает 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), что после достижения лимита запросы отклоняются, и что после истечения окна запросы снова работают.

Актуальность для безопасности: эндпоинты логина должны ограничивать частоту запросов для предотвращения брутфорс-атак. Проверяй что 429 возвращается после X неудачных попыток входа.

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