Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Границы валидации данных
Валидация информации может происходить на разных этапах жизненного цикла приложения, и выбор момента валидации критичен для надёжности и производительности системы.
На уровне приложения (на клиенте)
Обычно это первая линия защиты. Фронтенд валидирует введённые данные перед отправкой на сервер, чтобы дать пользователю немедленный фидбэк:
# На клиенте (JavaScript/React), но логика аналогична
# Быстрая синхронная валидация
if email and not is_valid_email(email):
show_error("Некорректный формат email")
return # Не отправляем на сервер
Плюсы: UX улучшается, экономим трафик и запросы к серверу.
На уровне API (граница приложения)
Это вторая и обязательная линия защиты. Каждый запрос должен валидироваться на сервере, даже если фронтенд уже проверил данные. Причины:
- Клиент может быть скомпрометирован или отключен
- Запросы могут приходить не только из вашего фронтенда (API, мобильное приложение, другие системы)
- Необходимо гарантировать целостность данных
from fastapi import FastAPI, HTTPException, Body
from pydantic import BaseModel, EmailStr, Field
app = FastAPI()
class UserInput(BaseModel):
email: EmailStr # Автоматическая валидация формата
age: int = Field(..., ge=0, le=150) # Возраст от 0 до 150
name: str = Field(..., min_length=1, max_length=100)
@app.post("/users")
async def create_user(user: UserInput):
# Pydantic уже провалидировал данные здесь
# Если данные невалидные, вернётся 422 Unprocessable Entity
return {"status": "created", "user": user}
На уровне бизнес-логики (domain layer)
После синтаксической валидации нужно проверить бизнес-правила. Это валидация смысла данных:
# domain/services/user_service.py
from domain.exceptions import ValidationError
class UserService:
def create_user(self, email: str, age: int) -> User:
# Синтаксис уже проверен на граница API
# Проверяем бизнес-правила
if self.user_repository.exists(email):
raise ValidationError("Пользователь с такой почтой уже существует")
if age < 18:
raise ValidationError("Пользователи должны быть старше 18 лет")
user = User(email=email, age=age)
self.user_repository.save(user)
return user
На уровне базы данных (последняя линия защиты)
Уровень БД защищает целостность данных от багов приложения:
CREATE TABLE users (
id UUID PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
age INT CHECK (age >= 0 AND age <= 150),
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
Важно: Ограничения БД не должны заменять валидацию в приложении, а дополнять её.
Когда валидация происходит в коде?
# Полный цикл валидации
# 1. Граница API — структурная валидация (Pydantic)
@app.post("/register")
async def register(user: UserRegisterSchema):
# user.email, user.password уже валидированы Pydantic
# 2. Бизнес-логика — семантическая валидация
try:
created_user = await user_service.register(user.email, user.password)
except ValidationError as e:
raise HTTPException(status_code=400, detail=str(e))
# 3. Если тут код, значит всё прошло валидацию
return {"status": "success", "user_id": created_user.id}
Иерархия валидации (от быстрой к медленной)
- Тип данных — быстро (int, str, bool) → Pydantic
- Формат — быстро (email, UUID, URL) → Regex или библиотеки
- Диапазон/длина — быстро (min/max, length) → Pydantic
- Уникальность/существование — медленно (запрос к БД) → Domain layer
- Бизнес-правила — зависит (сложная логика) → Domain layer
Лучшие практики
✅ Валидируй везде:
- На клиенте → быстрая обратная связь
- На сервере → безопасность
- В БД → целостность
✅ Структурную валидацию делай на границе:
from pydantic import BaseModel
class RequestSchema(BaseModel):
# Все проверки сюда
pass
✅ Бизнес-валидацию делай в domain layer:
class UserService:
def register(self, email: str, password: str):
# Здесь проверяем бизнес-правила
pass
❌ Не полагайся только на фронтенд
❌ Не валидируй в обработчике (handler), делай в сервисе
В итоге: информация проходит валидацию непрерывно, на каждом уровне архитектуры, начиная с фронтенда и заканчивая БД. Каждый уровень отвечает за свой вид проверок.