Коротко: 422 — это удобный и распространённый выбор для ошибок семантической/бизнес‑валидации, тогда как 400 — для синтаксических/структурных ошибок. Но есть нюанс: для конфликтов (duplicate key, уже существующий email) часто используют 409 Conflict. Главное — выбрать однозначную политику и задокументировать её.
Развернуто:
- 400 Bad Request (RFC 7231)
- Семантика: общий код для «неправильного запроса» со стороны клиента.
- Частые случаи: некорректный/повреждённый синтаксис (невалидный JSON), неверный Content‑Type, неразборный запрос.
- Можно использовать и для валидации полей, но он менее точен по смыслу.
- 422 Unprocessable Entity (RFC 4918 — WebDAV)
- Семантика: сервер понял синтаксис запроса (валидный JSON), но семантика/валидация содержимого не позволяет обработать запрос.
- Частые случаи: поля не проходят валидацию по бизнес‑правилам или схемам (например: пароль слишком короткий, формат поля корректен, но значение недопустимо).
- Широко используется в веб‑фреймворках (Rails по умолчанию возвращает 422 для невалидного объекта) и в JSON API практиках.
- 409 Conflict
- Семантика: запрос корректен, но не может быть выполнен из‑за конфликта с текущим состоянием ресурса.
- Частый случай: попытка создать сущность с уникальным полем, которое уже занято (email уже существует).
- Многие API предпочитают 409 именно для дублирующихся/конфликтующих операций.
Рекомендация для вашего случая
- Если JSON некорректен (не парсится) — 400.
- Если поле не соответствует бизнес‑правилу (например «пароль слишком короткий», «дата в прошлом не разрешена») — 422.
- Если пытаются создать ресурс, но это нарушает уникальность/идею целостности (email уже существует) — лучше вернуть 409 Conflict (или 422, если вы считаете это именно валидационной ошибкой). В реальной практике оба варианта встречаются, но 409 более семантически точен для конфликтов.
Практические советы
- Будьте последовательны и задокументируйте поведение (в OpenAPI/доках).
- Возвращайте теле ответа структурированную информацию об ошибках (поле, сообщение, код ошибки). Хорошая практика — использовать RFC 7807 (application/problem+json) или собственный формат с массивом ошибок.
- Примеры ответов:
- Синтаксический: 400
{
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "Invalid JSON syntax"
}
- Валидация поля: 422
{
"type": "/probs/validation",
"title": "Validation Failed",
"status": 422,
"errors": [
{"field": "password", "message": "Password must be at least 8 characters"}
]
}
- Уникальность (email уже существует): 409
{
"type": "/probs/conflict",
"title": "Conflict",
"status": 409,
"detail": "A user with this email already exists",
"errors": [{"field": "email", "message": "Email already taken"}]
}
Итого: для валидного JSON с ошибками в полях чаще всего применяют 422; для дубликатов/конфликтов — 409; для синтаксиса — 400. Выберите стратегию и описывайте её в документации API.