Ответ
Валидацию данных в веб-приложениях принято разделять на несколько уровней. Такой многоуровневый подход обеспечивает надежность и хороший пользовательский опыт.
1. Клиентский уровень (Frontend)
Проверка данных происходит в браузере пользователя до отправки на сервер.
- Цель: Улучшить UX, предоставив мгновенную обратную связь (например, поле email заполнено неверно).
- Технологии: Атрибуты HTML5 (
required,pattern), JavaScript. - Важно: Этот уровень легко обойти, поэтому он никогда не должен быть единственным.
<form>
<input type="email" name="email" required>
<input type="number" name="age" min="18">
</form>
2. Серверный уровень (Backend)
Это основной и обязательный уровень валидации. Проверка происходит после получения данных от клиента.
- Цель: Обеспечить целостность и безопасность данных, так как эту проверку нельзя обойти.
- Технологии: Библиотеки вроде Pydantic (Python), Joi (Node.js), встроенные средства фреймворков (Django Forms, DRF Serializers).
# Пример с Pydantic в FastAPI
from pydantic import BaseModel, EmailStr, Field
class UserCreate(BaseModel):
email: EmailStr
age: int = Field(gt=18, description="Возраст должен быть больше 18")
3. Уровень бизнес-логики
Проверка данных в контексте правил конкретного приложения, которые не могут быть выражены простыми типами.
- Цель: Гарантировать соответствие данных бизнес-требованиям.
- Примеры: Проверка, что баланс пользователя достаточен для совершения покупки; проверка, что промокод еще действителен.
class OrderService:
def create_order(self, user: User, order_data: Order):
if user.balance < order_data.total_price:
raise ValueError("Недостаточно средств на счете")
# ... логика создания заказа
4. Уровень базы данных (Database)
Последний рубеж защиты целостности данных, реализованный на уровне СУБД.
- Цель: Предотвратить запись некорректных данных даже в обход логики приложения.
- Технологии: Ограничения (
constraints)UNIQUE,NOT NULL,CHECK, внешние ключи (FOREIGN KEY).
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
age INTEGER CHECK (age > 0)
); Ответ 18+ 🔞
Слушай, а вот этот ваш многоуровневый подход к валидации — это, блядь, как строить крепость. Сначала частокол, потом стены, потом ров с крокодилами, а в центре ещё и башня с лучниками. Чтобы ни одна хуйня не пролезла. Иначе — пиздец.
1. Фронтенд, он же "для красоты и скорости"
Тут всё происходит прямо в браузере у юзера. Заполнил почту как попало — тут же ему красненьким подчеркнуло. Цель — чтобы не ждал, пока на сервер улетит и обратно ошибка прилетит. Но это, ёпта, как замок из песка. Ребёнок обойдёт, собака пробежит — и нет замка. Никогда, слышишь, НИКОГДА на него одного не рассчитывай. Это просто вежливость.
<form>
<input type="email" name="email" required>
<input type="number" name="age" min="18">
</form>
2. Бэкенд, он же "главный заслон"
А вот это уже, сука, серьёзно. Данные приплыли к тебе на сервер — тут их и надо проверять так, будто от этого зависит твоя жизнь. Потому что от этого и зависит жизнь твоего приложения. Любой распиздяй может отключить JS и слать тебе что угодно. Этот уровень обойти — нихуя не выйдет. Основа основ.
# Пример с Pydantic в FastAPI
from pydantic import BaseModel, EmailStr, Field
class UserCreate(BaseModel):
email: EmailStr
age: int = Field(gt=18, description="Возраст должен быть больше 18")
3. Бизнес-логика, он же "а по правилам-то можно?"
Тут уже не просто "почта похожа на почту", а "а хватит ли у Василия денег на этот золотой унитаз?". Правила, которые в саму структуру данных не впихнёшь. Если валидация на втором уровне — это проверка паспорта, то здесь — проверка, есть ли у тебя виза в эту конкретную страну под названием "Наш Сервис".
class OrderService:
def create_order(self, user: User, order_data: Order):
if user.balance < order_data.total_price:
raise ValueError("Недостаточно средств на счете")
# ... логика создания заказа
4. База данных, он же "последний оплот"
Представь, что все предыдущие уровни — твои охранники. А база данных — это, блядь, бетонный бункер с титановой дверью. Даже если все охранники уснули, проспали и обосрались, дверь должна держаться. UNIQUE, NOT NULL, CHECK — это такие засовы и запоры. На случай, если в логике приложения где-то затесался баг, и какая-то хуйня всё-таки попытается записаться.
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
age INTEGER CHECK (age > 0)
);
Вот и весь секрет. Каждый уровень — как фильтр. Чем их больше и чем они качественнее, тем чище вода на выходе. А иначе — жди беды, однажды какая-нибудь SQL-инъекция или отрицательный возраст пользователя тебе всю систему в говно превратят.