Документация: Swagger и ReDoc

Документация: Swagger и ReDoc FastAPI

Привет! Одна из лучших фишек FastAPI — это автоматическая документация. Она создаётся на основе вашего кода и всегда актуальна. Это экономит время и делает API удобным для разработчиков.

В этой статье мы разберём:

  • Swagger UI и ReDoc
  • Аннотации и описания
  • Pydantic модели в документации
  • Примеры запросов и ответов
  • Кастомизацию документации

Что нужно знать перед началом

Для этого урока тебе понадобится:

  • Установленный FastAPI и Uvicorn
  • Базовое понимание эндпоинтов

Совет: Документация FastAPI доступна по адресам /docs (Swagger) и /redoc (ReDoc).

Основная часть

Swagger UI и ReDoc

Swagger UI — интерактивная документация, где можно тестировать эндпоинты прямо в браузере.

ReDoc — альтернативная документация с более чистым дизайном.

# Swagger UI
http://localhost:8000/docs

# ReDoc
http://localhost:8000/redoc

Совет: Swagger UI удобен для тестирования, ReDoc — для чтения.

Базовые аннотации

FastAPI автоматически генерирует документацию из аннотаций.

from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}")
def get_user(user_id: int):
    """
    Получить пользователя по ID.
    """
    return {"user_id": user_id}

Совет: Докстринги добавляют описание в документацию.

Описание эндпоинтов

from fastapi import FastAPI, Query, Path, Body

app = FastAPI()

@app.get("/items/{item_id}")
def get_item(
    item_id: int = Path(..., description="ID товара"),
    q: str = Query(None, description="Поисковый запрос"),
    limit: int = Query(10, description="Лимит результатов")
):
    """
    Получить товар по ID с поиском.
    """
    return {"item_id": item_id, "q": q, "limit": limit}

Совет: Используй description для пояснения параметров.

Pydantic модели в документации

Pydantic модели автоматически отображаются в документации.

from pydantic import BaseModel, Field

class UserCreate(BaseModel):
    name: str = Field(..., description="Имя пользователя", min_length=2, max_length=50)
    email: str = Field(..., description="Email пользователя")
    age: int = Field(..., description="Возраст", ge=0, le=120)

@app.post("/users")
def create_user(user: UserCreate):
    """
    Создать нового пользователя.
    """
    return {"user": user}

Совет: Field добавляет описание и валидацию.

Примеры запросов и ответов

from fastapi import FastAPI, status
from pydantic import BaseModel

app = FastAPI()

class UserResponse(BaseModel):
    id: int
    name: str
    email: str

class UserCreate(BaseModel):
    name: str
    email: str

@app.post(
    "/users",
    response_model=UserResponse,
    status_code=status.HTTP_201_CREATED,
    description="Создание нового пользователя",
    summary="Create user"
)
def create_user(user: UserCreate):
    """
    **Создаёт нового пользователя.**

    - **name**: Имя пользователя
    - **email**: Email пользователя

    Возвращает созданного пользователя с ID.
    """
    return {"id": 1, "name": user.name, "email": user.email}

Совет: summary добавляет краткое описание, description — полное.

Теги для группировки

app = FastAPI()

@app.get("/users", tags=["users"])
def get_users():
    """Получить всех пользователей."""
    return [{"id": 1, "name": "Анна"}]

@app.get("/posts", tags=["posts"])
def get_posts():
    """Получить все посты."""
    return [{"id": 1, "title": "Пост"}]

Совет: Теги группируют эндпоинты в документации.

Кастомное описание приложения

from fastapi import FastAPI

app = FastAPI(
    title="Мой API",
    description="API для управления пользователями и постами.",
    version="1.0.0",
    contact={
        "name": "Имя автора",
        "email": "author@example.com",
    },
    license_info={
        "name": "MIT",
        "url": "https://opensource.org/licenses/MIT",
    },
    docs_url="/docs",
    redoc_url="/redoc",
    openapi_url="/openapi.json"
)

@app.get("/")
def root():
    return {"message": "Добро пожаловать!"}

Совет: contact и license_info добавляют контактную информацию.

Примеры ответов с разными статусами

from fastapi import FastAPI, HTTPException, status

app = FastAPI()

@app.get(
    "/users/{user_id}",
    responses={
        200: {"description": "Пользователь найден"},
        404: {"description": "Пользователь не найден"},
        422: {"description": "Ошибка валидации"}
    }
)
def get_user(user_id: int):
    if user_id == 0:
        raise HTTPException(status_code=404, detail="User not found")
    return {"id": user_id, "name": f"User {user_id}"}

Совет: Указывай все возможные статусы для лучшей документации.

Кастомизация OpenAPI

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    openapi_schema = get_openapi(
        title="Кастомный API",
        version="1.0.0",
        description="Кастомное описание",
        routes=app.routes,
    )
    openapi_schema["info"]["x-logo"] = {
        "url": "https://example.com/logo.png"
    }
    app.openapi_schema = openapi_schema
    return app.openapi_schema

app = FastAPI()
app.openapi = custom_openapi

@app.get("/")
def root():
    return {"message": "Hello, World!"}

Совет: Кастомизация OpenAPI позволяет добавлять логотипы и другие метаданты.

Полный пример

from fastapi import FastAPI, Query, Path, Body, HTTPException, status
from pydantic import BaseModel, Field
from typing import Optional

app = FastAPI(
    title="Blog API",
    description="API для управления блогом",
    version="1.0.0",
    contact={"name": "Admin", "email": "admin@example.com"},
    docs_url="/docs",
    redoc_url="/redoc"
)

class PostCreate(BaseModel):
    title: str = Field(..., min_length=1, max_length=200, description="Заголовок поста")
    content: Optional[str] = Field(None, description="Содержимое")
    published: bool = Field(False, description="Опубликован?")

class PostResponse(BaseModel):
    id: int
    title: str
    content: Optional[str]
    published: bool

@app.get(
    "/posts",
    response_model=list[PostResponse],
    tags=["posts"],
    description="Получить список всех постов",
    responses={200: {"description": "Список постов"}}
)
def get_posts():
    """Возвращает список всех постов."""
    return [
        {"id": 1, "title": "Post 1", "content": "Content", "published": True}
    ]

@app.get(
    "/posts/{post_id}",
    response_model=PostResponse,
    tags=["posts"],
    description="Получить пост по ID",
    responses={
        200: {"description": "Пост найден"},
        404: {"description": "Пост не найден"}
    }
)
def get_post(
    post_id: int = Path(..., description="ID поста", ge=1)
):
    """
    Получить пост по ID.

    - **post_id**: ID поста (целое число)
    """
    if post_id == 1:
        return {"id": 1, "title": "Post 1", "content": "Content", "published": True}
    raise HTTPException(status_code=404, detail="Post not found")

@app.post(
    "/posts",
    response_model=PostResponse,
    status_code=status.HTTP_201_CREATED,
    tags=["posts"],
    summary="Create a new post",
    description="Создаёт новый пост"
)
def create_post(post: PostCreate):
    """
    Создаёт новый пост.

    - **title**: Заголовок
    - **content**: Содержимое
    - **published**: Опубликован или нет
    """
    return {"id": 2, "title": post.title, "content": post.content, "published": post.published}

Задачи для закрепления

Задача 1. Добавь описание к эндпоинту /users.

Задача 2. Добавь теги для группировки эндпоинтов.

Задача 3. Добавь примеры ответов для разных статусов.

Задача 4. Кастомизируй название и описание приложения.

Задача 5. Настрой документацию с помощью Field.

Ответы:

Задача 1.

@app.get("/users")
def get_users():
    """Получить список всех пользователей."""
    return []

Задача 2.

@app.get("/users", tags=["users"])
def get_users():
    return []

@app.get("/posts", tags=["posts"])
def get_posts():
    return []

Задача 3.

@app.get("/users/{user_id}", responses={200: {"description": "OK"}, 404: {"description": "Not Found"}})
def get_user(user_id: int):
    if user_id == 0:
        raise HTTPException(status_code=404)
    return {"id": user_id}

Задача 4.

app = FastAPI(
    title="My API",
    description="My API description",
    version="1.0.0"
)

Задача 5.

class User(BaseModel):
    name: str = Field(..., description="Имя пользователя")

Нюансы и подводные камни

Документация доступна только в режиме разработки

В продакшене может быть отключена для безопасности.

Обновление документации

Документация обновляется автоматически при изменении кода.

OpenAPI версия

FastAPI использует OpenAPI 3.0.

Частые ошибки и как их избежать

Ошибка 1: Неправильное описание параметров

Используй PathQueryBody для описания.

Ошибка 2: Отсутствие response_model

Указывай response_model для документирования ответа.

Ошибка 3: Неполное описание статусов

Добавляй все возможные статусы в responses.

Шпаргалка

Что нужноКак пишется
Swagger UI/docs
ReDoc/redoc
Описание эндпоинтаdescription="..."
Краткое описаниеsummary="..."
Тегиtags=["users"]
Описание параметровPath(..., description="...")
Модель ответаresponse_model=UserResponse
Статусыresponses={200: {"description": "OK"}}

Заключение

Сегодня мы:

  • Узнали о Swagger UI и ReDoc
  • Добавляли описания и аннотации
  • Настраивали документацию
  • Практические примеры

КВИЗ

Что дальше?

Оцените статью
IMI-DS - PYTHON LERNEN
Содержание
Оглавление ×