Convenções para criar novos schemas Pydantic de entrada e revisar os existentes. O objetivo é rejeitar dados inválidos na camada de schema, antes de qualquer lógica de negócio ou consulta ao banco.
-
Schemas de entrada sempre com
model_config = ConfigDict(extra='forbid'). Campos não esperados no payload geramHTTP 422em vez de serem ignorados silenciosamente. Aplica-se a*Create,*Update, login, refresh e demais schemas que recebem dados do cliente. Schemas de resposta (*Read,*Public) não precisam. -
E-mails: usar
EmailStr(exige a dependênciaemail-validator). Normalizar com umfield_validatorque aplicastrip().lower(). -
Strings livres: definir limites. Use
Field(min_length=..., max_length=...)sensatos (ex.:full_namecommin_length=1emax_length=255). Campos opcionais usamT | None, não valores mágicos. -
Campos de valor fixo (status, tipo): usar
Enumdo Python com o tipo correspondente do Pydantic, nuncastrlivre. -
IDs: validar o formato (ex.: UUID) via
field_validator, não aceitar qualquer string. A validação de existência no banco continua no service. -
Normalizar entrada no schema: remover espaços extras (
strip()) e normalizar caixa onde fizer sentido (e-mail), para que dados "sujos" não cheguem à camada de serviço. -
Validação de negócio simples vai no schema; validação que depende do banco (ex.: unicidade de e-mail, existência de role) permanece no service.
from pydantic import BaseModel, ConfigDict, EmailStr, Field, field_validator
class ProfileCreate(BaseModel):
model_config = ConfigDict(extra='forbid')
email: EmailStr = Field(..., description='Valid email address')
full_name: str | None = Field(default=None, min_length=1, max_length=255)
@field_validator('email')
@classmethod
def normalize_email(cls, value: str) -> str:
return value.strip().lower()O handler global (app/core/error_handlers.py) responde HTTP 422 com
details no formato:
{
"error": {
"type": "RequestValidationError",
"message": "Validation error",
"details": [
{"field": "email", "message": "value is not a valid email address: ..."}
]
},
"status": 422,
"path": "/api/auth/register",
"method": "POST"
}O campo field indica o(s) campo(s) problemático(s); message traz a razão
legível, sem dados sensíveis.