Пути и query-параметры в FastAPI

Пути и query-параметры в FastAPI FastAPI

Привет! В FastAPI данные могут передаваться разными способами. Сегодня мы разберём два основных: параметры пути (path parameters) и параметры запроса (query parameters). Они позволяют создавать гибкие и мощные API.

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

  • Параметры пути (path parameters)
  • Параметры запроса (query parameters)
  • Типы данных и валидацию
  • Примеры из реальной жизни

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

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

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

Совет: FastAPI использует аннотации типов Python для автоматической валидации параметров.

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

Параметры пути (path parameters)

Параметры пути передаются непосредственно в URL.

from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id, "name": f"Пользователь {user_id}"}

@app.get("/products/{product_id}")
def get_product(product_id: int):
    return {"product_id": product_id, "name": f"Товар {product_id}"}

Совет: Имя параметра в фигурных скобках должно совпадать с именем аргумента функции.

Типы параметров пути

FastAPI автоматически преобразует параметры к указанным типам.

@app.get("/posts/{post_id}")
def get_post(post_id: int):           # Автоматически в int
    return {"post_id": post_id}

@app.get("/files/{file_path:path}")   # path — для путей со слешами
def get_file(file_path: str):
    return {"file": file_path}

Поддерживаемые типы:

ТипОписаниеПример
intЦелое число/users/123
strСтрока/users/anna
floatДробное число/price/99.99
boolЛогический тип/active/true
pathПуть со слешами/files/docs/readme.txt

Совет: Используй path для параметров, которые могут содержать слеши.

Несколько параметров пути

@app.get("/posts/{year}/{month}/{day}")
def get_post_by_date(year: int, month: int, day: int):
    return {"date": f"{year}-{month:02d}-{day:02d}"}

Параметры запроса (query parameters)

Параметры запроса передаются после ? в URL.

@app.get("/search")
def search(q: str, page: int = 1, limit: int = 10):
    return {
        "query": q,
        "page": page,
        "limit": limit,
        "results": [f"Результат {i}" for i in range(1, limit + 1)]
    }

Пример запроса: /search?q=fastapi&page=2&limit=5

Совет: Параметры запроса указываются в функции как обычные аргументы. Если есть значение по умолчанию — параметр необязательный.

Опциональные параметры

@app.get("/items/")
def list_items(skip: int = 0, limit: int = 10):
    return {"skip": skip, "limit": limit}

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

/items/          # skip=0, limit=10
/items/?skip=5   # skip=5, limit=10
/items/?limit=3  # skip=0, limit=3

Валидация параметров

FastAPI автоматически валидирует параметры.

@app.get("/users/{user_id}")
def get_user(user_id: int):  # Если передать строку, вернёт ошибку 422
    return {"user_id": user_id}

Ошибка при неверном типе:

# Запрос: /users/abc
# Ответ: 422 Unprocessable Entity

Совет: Аннотации типов в FastAPI — это не просто подсказки, это валидация.

Обязательные и необязательные параметры

from typing import Optional

@app.get("/products/")
def get_products(
    category: Optional[str] = None,
    min_price: Optional[float] = None,
    max_price: Optional[float] = None
):
    filters = {}
    if category:
        filters["category"] = category
    if min_price:
        filters["min_price"] = min_price
    if max_price:
        filters["max_price"] = max_price
    return {"filters": filters}

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

from fastapi import FastAPI
from typing import Optional

app = FastAPI(title="API с параметрами")

# Параметры пути
@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id}

# Параметры запроса
@app.get("/search")
def search(q: str, page: int = 1, limit: int = 10):
    return {
        "query": q,
        "page": page,
        "limit": limit,
        "total": limit
    }

# Комбинация
@app.get("/posts/{year}/{month}")
def get_posts(year: int, month: int, sort: str = "desc", limit: int = 10):
    return {
        "year": year,
        "month": month,
        "sort": sort,
        "limit": limit
    }

# Опциональные параметры
@app.get("/products/")
def get_products(
    category: Optional[str] = None,
    min_price: Optional[float] = None,
    max_price: Optional[float] = None
):
    return {
        "filters": {
            "category": category,
            "min_price": min_price,
            "max_price": max_price
        }
    }

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

Задача 1. Создай эндпоинт /users/{user_id} с параметром user_id типа int.

Задача 2. Создай эндпоинт /search с параметрами q (обязательный) и page (необязательный).

Задача 3. Создай эндпоинт /posts/{year}/{month}.

Задача 4. Добавь опциональный параметр category в эндпоинт /products/.

Задача 5. Что произойдёт, если передать строку в параметр user_id: int?

Ответы:

Задача 1.

@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id}

Задача 2.

@app.get("/search")
def search(q: str, page: int = 1):
    return {"query": q, "page": page}

Задача 3.

@app.get("/posts/{year}/{month}")
def get_posts(year: int, month: int):
    return {"year": year, "month": month}

Задача 4.

@app.get("/products/")
def get_products(category: Optional[str] = None):
    return {"category": category}

Задача 5.

# Вернёт ошибку 422 Unprocessable Entity

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

  • FastAPI автоматически валидирует типы параметров. Если тип не совпадает — возвращается 422.
  • Параметры пути обязательны. Если их нет в URL — ошибка 404.
  • Параметры запроса (query) могут быть опциональными, если указано значение по умолчанию.
  • Параметры пути и запроса не могут иметь одинаковые имена.
  • path — специальный тип, позволяющий передавать пути со слешами.
  • При использовании Optional с None параметр становится необязательным.
  • Порядок параметров в функции не важен — FastAPI определяет их по типу и имени.

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

Ошибка 1: Имя параметра пути не совпадает с аргументом

Неправильно:

@app.get("/users/{user_id}")
def get_user(id: int):   # Ошибка! Имя должно быть user_id
    pass

Правильно:

@app.get("/users/{user_id}")
def get_user(user_id: int):
    pass

Ошибка 2: Неправильный тип конвертера

Используй int для чисел, str для строк, path для путей.

Ошибка 3: Забыл Optional для необязательных параметров

q: Optional[str] = None

Шпаргалка

Что нужноКак пишется
Параметр пути@app.get("/users/{user_id}")
Параметр запросаdef search(q: str, page: int = 1)
Тип intuser_id: int
Тип strname: str
Тип floatprice: float
Тип pathfile_path: path
Опциональный параметрOptional[str] = None

Заключение

Сегодня мы:

  • Изучили параметры пути
  • Изучили параметры запроса
  • Разобрали типы данных
  • Научились валидировать параметры

КВИЗ

Что дальше?

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