– это современный веб-фреймворк для Python, который был разработан с целью обеспечения высокой производительности и эффективности в разработке веб-сервисов. Он основан на стандартах Python 3.6+ и полностью совместим с асинхронными возможностями языка.
Преимущества FastAPI:
Недостатки FastAPI:
Это простой пример использования FastAPI для создания минимальногр веб-приложения.
from fastapi import FastAPI
app = FastAPI()
@app.get("/", name="hello")
async def root():
return {"message": "Hello World"}
from fastapi import FastAPI
: импортируем класс FastAPI
из библиотеки FastAPI, который используется для создания веб-приложений.app = FastAPI()
: Здесь создается экземпляр приложения FastAPI, который будет использоваться для определения маршрутов и обработки запросов.@app.get("/", name="hello")
: Это декоратор, который связывает функцию root()
с маршрутом /
и указывает на то, что она обрабатывает GET-запросы.def root()
: Это определение функции обработчика для маршрута /
. Она возвращает JSON-ответ с текстом сообщения.Запуск командой
Маршруты определяют, как приложение обрабатывает запросы. Они связывают функции обработчики с конкретными path’ами (сервиса). В FastAPI они определяются с помощью декораторов и объектами API.
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
В этом примере мы определяем маршрут GET /items/{item_id}
, который принимает параметр item_id
и возвращает JSON-объект с этим параметром.
FastAPI предоставляет удобный инструмент для структурирования вашего приложения, сохраняя при этом всю гибкость. Для использования APIRouter
, вы создаете экземпляр класса APIRouter
и определяете на нем маршруты. Затем вы можете подключить этот роутер к основному экземпляру FastAPI с помощью метода include_router
.
Пример:
from fastapi import FastAPI, APIRouter
app = FastAPI()
v1_router = APIRouter(prefix="/v1")
@v1_router.get("/get_message/")
def get_message():
"""
Some endpoint.
"""
return {
"message": "Hello from APIRouter",
}
v2_router = APIRouter(prefix="/v2")
@v2_router.get("/get_message/")
def get_message_new():
"""
Some endpoint.
"""
return {
"message": "Hello from APIRouter",
"response_date": "12/04/2024",
}
app.include_router(v1_router, prefix="/api")
app.include_router(v2_router, prefix="/api")
В этом примере:
APIRouter
с именем v1_router
и v2_router
.GET /
на v1_router
, который возвращает сообщение “Hello from APIRouter”.GET /
на v2_router
, который возвращает сообщение “Hello from APIRouter” дополнительным параметром обновленной версии API.v1_router
к основному приложению FastAPI с префиксом /api/v1/get_message/
.v2_router
к основному приложению FastAPI с префиксом /api/v2/get_message/
.Теперь, когда вы запустите приложение FastAPI, вы сможете обратиться к маршруту GET /api/v2/get_message/
для получения ответа от APIRouter
.
Использование APIRouter
делает ваш код более организованным и управляемым, особенно когда ваше API растет в сложности и размере.
GET
для получения данных,POST
для создания новых ресурсов,PUT
для обновления существующих ресурсов,DELETE
для удаления ресурсов,PATCH
для частичного обновления ресурсов,OPTIONS
для получения информации о возможностях сервера,HEAD
для получения заголовков без тела ответа.Пример:
Полный список методов можно найти в RFC 9110. Это документ, который описывает стандарты.
Соблюдение этого RFC не является обязательным, и методы могут быть использованы по своему усмотрению, например, можно обрабатывать создание ресурсов с помощью POST.
Важно помнить, что даже стандартные методы можно использовать гибко, а также при необходимости можно создать кастомные методы для специфичных задач.
Модели Pydantic используются для определения структуры данных входящих и исходящих запросов. Они обеспечивают валидацию данных и автоматическую сериализацию между форматами JSON и Python.
Класс ConfigDict
в Pydantic используется для определения дополнительных настроек модели данных. Атрибут json_schema_extra
этого класса позволяет добавлять дополнительные метаданные или примеры данных для документации по API, улучшая читаемость и понятность документации.
Пример:
from pydantic import BaseModel, ConfigDict
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
model_config = ConfigDict(
json_schema_extra={
"example": {
"name": "товар #1",
"description": "описание товара #1",
"price": 17.50,
"tax": 8.5,
}
}
)
В этом примере мы создаем модель Item
, которая содержит поля name
, description
, price
и tax
. Поля name
и price
обязательны для заполнения, а поля description
и tax
являются необязательными. Pydantic автоматически выполняет валидацию и преобразование типов данных, если это необходимо.
FastAPI позволяет определять параметры входящих запросов. Вот несколько примеров:
Параметры пути (Path parameters): Определяются в URL-адресе и используются для передачи данных.
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
Отправка запроса
FastAPI самостоятельно парсит параметры полученные из запроса, сопоставляя типы на основе аннотаций.
Параметры запроса (Query parameters): Передаются в URL-адресе через символ вопроса и амперсанд.
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
Отправка запроса
Тело запроса (Request Body): Передается в теле HTTP-запроса и используется для передачи структурированных данных, например, JSON или формы.
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
Отправка запроса
FastAPI предоставляет удобные методы для создания ответов на запросы. Например, JSONResponse
для возврата JSON-данных или HTMLResponse
для возврата HTML-контента.
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pydantic import BaseModel
app = FastAPI()
@app.get("/items/")
def read_item(item_id: int):
return JSONResponse(
status_code=200,
content={"name": "Item 1", "item_id": item_id, "description": "Item description"}
)
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: Union[str, None] = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: Union[str, None] = None
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
return user
В примере выше, метод create_user
принимает данные о пользователе в виде модели UserIn
и возвращает данные о созданном пользователе в виде модели UserOut
. Использование response_model=UserOut
указывает на то, что FastAPI должен проверить, что возвращаемые данные соответствуют модели UserOut
и преобразует их в JSON согласно структуре модели.
FastAPI предоставляет простой доступ к кодам статуса ответов HTTP, таким как 200 (OK), 404 (Not Found) и т. д.
from fastapi import FastAPI, status
app = FastAPI()
@app.post("/items/", status_code=status.HTTP_201_CREATED)
async def create_item(item: Item):
# Обработка создания элемента...
return {"message": "Item created successfully"}
Здесь мы возвращаем статус создания ресурса (201 Created) вместе с сообщением об успешном создании элемента. Мы так же можем передавать целое число, которое соответствует коду ошибки.
Фоновые задачи позволяют выполнять асинхронные операции в фоне во время обработки запросов.
Особенности и пример использования фоновых задач в FastAPI:
from fastapi import FastAPI, BackgroundTasks
app = FastAPI()
async def send_logs(data: dict):
# отправка данных в БД...
@app.post("/data/")
async def create_data(data: str, background_tasks: BackgroundTasks):
background_tasks.add_task(send_logs, data)
return {"message": "Data received and processing started"}
Этот пример демонстрирует добавление фоновой задачи для обработки полученных данных без блокировки основного потока выполнения.
Но есть несколько случаев, когда может быть разумным переходить от использования Background Tasks к Celery и т.п. инструментам:
FastAPI предоставляет удобные методы для получения файлов из запросов и их обработки.
from fastapi import FastAPI, UploadFile, File
app = FastAPI()
@app.post("/upload/")
async def upload_file(file: UploadFile = File(...)):
contents = await file.read()
return {"filename": file.filename, "contents": contents}
Этот пример позволяет загружать файлы и возвращать их содержимое.
💡 необходимо установить модуль python-multipart который скачивает батчами файлы.
FastAPI предоставляет возможность определять обработчики событий при запуске и остановке приложения с помощью так называемых “lifespan events” (событий жизненного цикла). Эти события позволяют выполнять определенные действия при запуске и остановке сервера, что может быть полезно, например, для подготовки и очистки ресурсов.
Вот более подробное описание событий при запуске и остановке приложения в FastAPI:
@app.on_event("startup")
.@app.on_event("shutdown")
.from fastapi import FastAPI
from loguru import logger
app = FastAPI()
@app.on_event("startup")
async def startup_event():
app.state.client_db = create_client()
logger.info("Application initialized")
@app.on_event("shutdown")
async def shutdown_event():
app.state.client_db.close()
logger.info("Application shutdown")
В поздних версиях предлагается их заменить на функцию lifespan, в которой описывается логика операций при старте и завершении приложения.
Middleware - представляет собой механизм для обработки запросов до и после их обработки соответствующим обработчиком маршрута. Это позволяет выполнять дополнительные действия, такие как аутентификация, логирование, обработка ошибок и многое другое, на каждом этапе обработки запроса.
Типы middleware:
Рассмотрим пример создания middleware в Starlette, который будет отправлять логи с мета-информацией о запросе в базу данных, вам нужно будет создать функцию, которая будет обернута в middleware. Вот пример кода, который может быть использован для этой цели:
from starlette.middleware.base import (
BaseHTTPMiddleware,
RequestResponseEndpoint,
)
from starlette.requests import Request
from starlette.responses import Response
import json
from datetime import datetime
class LoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(
self, request: Request, call_next: RequestResponseEndpoint
) -> Response:
# Формируем словарь с мета-информацией
meta_info = {
"timestamp": datetime.now(),
"client_ip": request.client.host,
"cookies": request.cookies,
"user_agent": request.headers.get("user-agent"),
}
await self.save_to_db(meta_info)
# Продолжаем обработку запроса
response = await call_next(request)
return response
async def save_to_db(self, meta_info: str) -> None:
"""Функция для записи мета-информации в базу данных."""
pass
# Затем добавьте middleware в FastAPI-приложение
from fastapi import FastAPI
app = FastAPI()
app.add_middleware(LoggingMiddleware)
В этом примере, LoggingMiddleware
является классом, который наследуется от BaseHTTPMiddleware
и определяет как middleware будет работать. Функция dispatch
вызывается каждый раз, когда приходит запрос, и она может использоваться для записи мета-информации о запросе в базу данных.
Обратите внимание, что save_to_db
- это функция, для работы с базами данных асинхронно, вы можете использовать библиотеки, такие как asyncpg
для PostgreSQL или aiomysql
для MySQL.