Представьте, что ваш сервер — это ночной клуб, а входные данные — это люди, пытающиеся пройти на вечеринку. Если вы не проверяете, кто заходит (возраст, наличие билета и т.д.), у вас скоро начнётся хаос. В случае API хаос — это ошибки, уязвимости и поломка системы. Валидация входных данных позволяет убедиться, что сервер получает именно те данные, которые он ожидает. Она защищает от случайного ввода неверных данных пользователем и даже от умышленных попыток взлома.
В FastAPI Pydantic модели позволяют нам с легкостью автоматизировать эту проверку и сделать её не только безопасной, но и удобной.
Использование Pydantic моделей для валидации запросов
Давайте начнем с простого примера: мы хотим создать эндпоинт, который принимает данные пользователя (имя, возраст и email) и возвращает их обратно, если они прошли проверку.
Пример
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
# Создаем Pydantic-модель для валидации данных
class User(BaseModel):
name: str
age: int
email: EmailStr
@app.post("/users/")
async def create_user(user: User):
# Если данные в user прошли валидацию — возвращаем их
return user
Объяснение:
- Мы создали класс
User, унаследованный отBaseModel. Эта модель определяет схему входных данных. - Для поля
emailмы использовали специальный типEmailStrиз Pydantic, который автоматически проверяет, что переданная строка является корректным email-адресом. - В эндпоинте мы принимаем
userкак аргумент функции — FastAPI автоматически проверяет, что переданные данные соответствуют моделиUser.
Теперь, если вы отправите запрос с некорректными данными:
curl -X POST "http://127.0.0.1:8000/users/" -H "Content-Type: application/json" -d '{"name": "Alice", "age": "not_a_number", "email": "not_an_email"}'
Вы получите ответ:
{
"detail": [
{
"loc": ["body", "age"],
"msg": "value is not a valid integer",
"type": "type_error.integer"
},
{
"loc": ["body", "email"],
"msg": "value is not a valid email address",
"type": "value_error.email"
}
]
}
FastAPI сам заботится о проверке данных и возвращает подробные сообщения об ошибках.
Передача данных через тело запроса
Модели Pydantic идеально подходят для данных, передаваемых через тело запроса (Request Body). FastAPI автоматически ожидает JSON-структуру, соответствующую модели.
Пример: регистрация книги
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
# Модель данных для книги
class Book(BaseModel):
title: str
author: str
pages: int
@app.post("/books/")
async def add_book(book: Book):
return {"message": f"Book '{book.title}' has been successfully added!"}
Попробуем отправить запрос:
curl -X POST "http://127.0.0.1:8000/books/" -H "Content-Type: application/json" -d '{"title": "1984", "author": "George Orwell", "pages": 328}'
Ответ:
{
"message": "Book '1984' has been successfully added!"
}
Попробуйте отправить запрос с некорректными данными, например, пропустив поле title. FastAPI мгновенно уведомит вас об этом:
{
"detail": [
{
"loc": ["body", "title"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
Использование Pydantic для обработки Query Parameters
Не только данные в теле запроса заслуживают валидации. Часто встречается необходимость проверять данные, переданные через параметры запроса (Query Parameters).
Пример с Query Parameters
Представим, что пользователь хочет найти книгу по её автору. Мы сделаем эндпоинт, который принимает параметр author и использует Pydantic для проверки.
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/books/")
async def get_books(author: Annotated[str, Query(min_length=3, max_length=50)]):
return {"message": f"Поиск книг автора: {author}"}
Преимущества использования Annotated:
- Явное определение метаданных:
Annotatedпозволяет четко разделять тип данных и связанные с ним метаданные, что улучшает читаемость и поддержку кода. - Безопасность типов: Использование
Annotatedпомогает избежать потенциальных ошибок, связанных с неправильной обработкой значений по умолчанию.
Рекомендуется использовать Annotated для более явного и безопасного определения параметров в FastAPI. Однако, если вы предпочитаете более краткую запись и уверены в корректной обработке значений по умолчанию, вариант без Annotated также допустим.
Попробуем запрос:
curl -X GET "http://127.0.0.1:8000/books/?author=Orwell"
Успешный ответ:
{
"message": "Searching books by author: Orwell"
}
Если длина параметра author будет меньше 3 символов, FastAPI вернет ошибку:
{
"detail": [
{
"loc": ["query", "author"],
"msg": "ensure this value has at least 3 characters",
"type": "value_error.any_str.min_length",
"ctx": {"limit_value": 3}
}
]
}
Валидация Path Parameters
В FastAPI используются Path Parameters для передачи идентификаторов и других данных в URL. Pydantic позволяет также валидировать такие параметры.
Приведём пример. Разработаем получение книги по ID.
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/books/{book_id}")
async def get_book(book_id: int = Path(..., ge=1)):
return {"message": f"Book with ID {book_id}"}
Объяснение:
- Используя
Path(...), мы задаём ограничения на параметр пути. В данном случаеbook_idдолжен быть целым числом больше или равным 1 (ge=1). - Если переданный идентификатор не соответствует этим требованиям, FastAPI вернет сообщение об ошибке.
Попробуем запрос:
curl -X GET "http://127.0.0.1:8000/books/5"
Успешный ответ:
{
"message": "Book with ID 5"
}
Если передать некорректный ID, например, -3, результат будет таким:
{
"detail": [
{
"loc": ["path", "book_id"],
"msg": "ensure this value is greater than or equal to 1",
"type": "value_error.number.not_ge",
"ctx": {"limit_value": 1}
}
]
}
Типичные ошибки и особенности
Работая с валидацией в Query, Path и Request Body, важно помнить:
- Если вы забыли указать поле как обязательное (
...), FastAPI автоматически сделает его опциональным со значениемNone. - Порядок аргументов в эндпоинте (Path, Query, Body) имеет значение. FastAPI использует их для разделения данных.
- Не забывайте про встроенные типы Pydantic, такие как
EmailStr,IPv4Address,PositiveInt— они упрощают жизнь.
Теперь, когда вы знаете, как валидировать входные данные, вы уверенно можете сказать, что вы — опытный "вышибала", который не пропустит плохие данные на закрытую API-вечеринку.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ