Короткий ответ
Pydantic описывает схему входных данных декларативно (типы, ограничения, кастомные валидаторы) и собирает все ошибки валидации за один проход; клиенту стоит вернуть единый ответ со списком всех невалидных полей и причин, а не только первую найденную ошибку.
Как это работает подробнее
Pydantic проверяет каждое поле по отдельности и аккумулирует список ошибок (ValidationError.errors()), а не останавливается на первой — это позволяет клиенту исправить все проблемы за одну итерацию, а не отправлять запрос заново после каждой отдельной ошибки.
Пример кода
example.py
from pydantic import BaseModel, field_validator, model_validator
from datetime import date
class CreateBooking(BaseModel):
start_date: date
end_date: date
guests: int
@field_validator("guests")
@classmethod
def guests_positive(cls, v):
if v < 1:
raise ValueError("guests must be at least 1")
return v
@model_validator(mode="after")
def check_dates(self):
if self.end_date <= self.start_date:
raise ValueError("end_date must be after start_date")
return selfЧто использовать на практике
- Рекомендация. кастомные бизнес-правила (например, "дата окончания должна быть позже даты начала") реализуются через
model_validator/field_validator, а не проверяются вручную после десериализации — это сохраняет единый формат ошибок для всех видов невалидности. Важно решить, насколько подробным должно быть сообщение об ошибке для внешнего API (не раскрывать внутренние детали реализации) против внутреннего API (можно быть более техническим).
Подводные камни
- Риски. проверять только первое невалидное поле и прерывать проверку остальных, вынуждая клиента отправлять запрос несколько раз для нахождения всех проблем; возвращать текст ошибки Pydantic "как есть" без преобразования в клиентский формат, из-за чего структура ответа об ошибке становится нестабильной между версиями библиотеки.