Валидация данных является ключевым аспектом разработки веб-приложений. Когда ваш API принимает данные от пользователей, важно убедиться, что эти данные корректны и соответствуют ожидаемым форматам. FastAPI использует Pydantic для автоматической валидации данных, что позволяет разработчикам писать меньше кода и концентрироваться на логике приложения.

Основные концепции Pydantic

Pydantic — это библиотека для проверки типов данных и валидации данных в Python. Она позволяет создавать модели данных, которые автоматически проверяют, соответствуют ли переданные данные заданным типам и условиям. Pydantic широко используется в FastAPI для валидации входных данных запросов и ответов.

Ключевые возможности Pydantic:

  • Автоматическая проверка типов: Pydantic автоматически проверяет типы данных и конвертирует их в указанные типы.
  • Обработка значений по умолчанию: Можно задать значения по умолчанию для полей модели.
  • Обработка ошибок: Pydantic генерирует детализированные сообщения об ошибках, если данные не соответствуют заданным условиям.
  • Декларативный стиль: Модели данных создаются декларативно с использованием аннотаций типов Python.

Создание моделей данных с Pydantic

Создадим несколько моделей данных, чтобы продемонстрировать возможности Pydantic. Мы создадим простую CRM-систему с моделями для клиентов и заказов.

Пример 1: Модель данных для клиента

from pydantic import BaseModel, EmailStr
from typing import Optional

class Customer(BaseModel):
    id: int
    name: str
    email: EmailStr
    address: Optional[str] = None

В этой модели Customer содержит следующие поля:

  • id: целое число (обязательное поле)
  • name: строка (обязательное поле)
  • email: строка, соответствующая формату email (обязательное поле)
  • address: строка (необязательное поле)

Пример 2: Модель данных для заказа

from pydantic import BaseModel
from typing import List

class OrderItem(BaseModel):
    item_id: int
    quantity: int

class Order(BaseModel):
    order_id: int
    customer_id: int
    items: List[OrderItem]
    total_price: float

В этой модели Order содержит следующие поля:

  • order_id: целое число (обязательное поле)
  • customer_id: целое число (обязательное поле)
  • items: список объектов OrderItem (обязательное поле)
  • total_price: число с плавающей точкой (обязательное поле)

Использование моделей данных в FastAPI

Теперь, когда у нас есть модели данных, мы можем использовать их для валидации входных данных в FastAPI. Создадим эндпоинты для создания клиентов и заказов.

Пример 3: Эндпоинт для создания клиента

from fastapi import FastAPI

app = FastAPI()

@app.post("/customers/")
async def create_customer(customer: Customer):
    return customer

В этом примере мы определили эндпоинт /customers/, который принимает POST-запрос. Входные данные должны соответствовать модели Customer. FastAPI автоматически валидирует данные и передаст их в функцию create_customer, если они соответствуют модели.

Пример 4: Эндпоинт для создания заказа

@app.post("/orders/")
async def create_order(order: Order):
    return order

Здесь мы определили эндпоинт /orders/, который принимает POST-запрос с данными, соответствующими модели Order.

Обработка ошибок валидации

Когда данные не соответствуют модели, Pydantic генерирует детализированные сообщения об ошибках. FastAPI автоматически обрабатывает эти ошибки и возвращает понятные ответы клиенту.

Пример 5: Пример ошибки валидации

Отправьте POST-запрос на /orders/ с некорректными данными:

{
    "order_id": 1,
    "customer_id": 123,
    "items": [
        {
            "item_id": 1,
            "quantity": "three"
        }
    ],
    "total_price": 100.0
}

Ответ будет содержать информацию об ошибке:

{
    "detail": [
        {
            "loc": ["body", "items", 0, "quantity"],
            "msg": "value is not a valid integer",
            "type": "type_error.integer"
        }
    ]
}

Этот ответ указывает, что значение поля quantity должно быть целым числом, а не строкой.

Дополнительные возможности

Pydantic предоставляет не только базовую проверку типов данных, но и ряд дополнительных функций, которые значительно упрощают разработку веб-приложений. В дополнение к уже рассмотренным концепциям, рассмотрим следующие возможности:

Валидация значений

Помимо проверки типов данных, Pydantic позволяет задавать дополнительные условия для проверки значений. Это может включать проверку диапазона числовых значений, минимальной или максимальной длины строк и других параметров. Рассмотрим пример:

from pydantic import BaseModel, constr, condecimal

class Product(BaseModel):
    name: constr(min_length=3, max_length=50)
    price: condecimal(gt=0)

Здесь constr используется для проверки строки по длине, а condecimal для проверки положительного числа с плавающей точкой.

Обработка значений по умолчанию

Часто требуется задать значения по умолчанию для полей модели. Pydantic поддерживает это с помощью аргументов по умолчанию в объявлении полей:

from pydantic import BaseModel

class User(BaseModel):
    id: int
    name: str = 'John Doe'
    age: int = 25

Здесь name и age имеют значения по умолчанию, которые будут присвоены, если они не будут переданы при создании экземпляра модели.

Аннотации для вложенных моделей и контейнеров

Pydantic позволяет объявлять аннотации для вложенных моделей и контейнеров (например, списков или словарей), что обеспечивает рекурсивную валидацию данных:

from pydantic import BaseModel
from typing import List

class Item(BaseModel):
    name: str
    price: float

class Cart(BaseModel):
    owner_id: int
    items: List[Item]

Здесь Cart содержит список items, каждый из которых должен быть экземпляром Item.

Кастомные валидаторы

Для более сложных проверок данных можно использовать кастомные валидаторы, которые являются методами модели и вызываются при валидации. Пример кастомного валидатора:

from pydantic import BaseModel, validator

class User(BaseModel):
    username: str
    password: str

    @validator('password')
    def validate_password(cls, v):
        assert len(v) >= 6, 'password must be at least 6 characters'
        return v

Этот валидатор проверяет, что пароль состоит как минимум из 6 символов.