Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Параметры пути
path_params

Параметры пути

Динамические маршруты, валидация параметров, типы данных

Открыть лабораториюv1.0Запускается локально из публичного репозитория

Параметры пути (Path Parameters)

Параметры пути позволяют создавать динамические маршруты вроде /users/{user_id}. В этой теме вы научитесь валидировать параметры, накладывать ограничения и использовать продвинутые возможности.

#Базовый синтаксис

Параметры пути объявляются в фигурных скобках:

from fastapi import FastAPI app = FastAPI() @app.get('/users/{user_id}') def get_user(user_id: int): return {'user_id': user_id}

При запросе /users/5 вы получите:

{"user_id": 5}

#Как это работает?

  1. FastAPI видит {user_id} в пути
  2. Находит параметр user_id в сигнатуре функции
  3. Извлекает значение из URL
  4. Преобразует к указанному типу (int)
  5. Передаёт в функцию

#Типы данных

FastAPI поддерживает любые Python-типы:

@app.get('/items/{item_id}') def get_item(item_id: int): return {'type': 'int', 'value': item_id} @app.get('/products/{product_id}') def get_product(product_id: float): return {'type': 'float', 'value': product_id} @app.get('/flags/{flag_id}') def get_flag(flag_id: bool): return {'type': 'bool', 'value': flag_id}

#Преобразование типов

ТипПримеры URLРезультат
int/items/4242
float/products/3.143.14
bool/flags/true, /flags/FalseTrue, False
str/names/alex"alex"

#Булевы параметры

FastAPI распознаёт следующие значения как True:

  • "true", "True", "TRUE", "1", "yes", "on"

Как False:

  • "false", "False", "FALSE", "0", "no", "off"

Запрос /flags/yes → flag_id = True

#Валидация с Path()

Иногда нужно больше, чем просто проверка типа. Например:

  • Число должно быть от 1 до 1000
  • Строка должна соответствовать шаблону
  • Значение не может быть меньше определённого

Для этого используется Path():

from fastapi import FastAPI, Path app = FastAPI() @app.get('/items/{item_id}') def get_item(item_id: int = Path(..., title="ID элемента", description="Уникальный идентификатор")): return {'item_id': item_id}

#Что делает Path()?

  • ... (Ellipsis) — означает, что параметр обязателен (нельзя опустить)
  • title — заголовок для документации
  • description — подробное описание

#Альтернативный синтаксис

Можно использовать аннотацию Annotated (Python 3.10+):

from typing import Annotated from fastapi import FastAPI, Path app = FastAPI() @app.get('/items/{item_id}') def get_item(item_id: Annotated[int, Path(title="ID элемента", description="Уникальный идентификатор")]): return {'item_id': item_id}

Этот синтаксис предпочтителен в Pydantic v2 и новых версиях FastAPI.

#Ограничения для чисел

from fastapi import FastAPI, Path app = FastAPI() @app.get('/items/{item_id}') def get_item( item_id: int = Path( ..., title="ID элемента", ge=1, # больше или равно (greater or equal) le=1000, # меньше или равно (less or equal) gt=0, # строго больше (greater than) lt=1001, # строго меньше (less than) ) ): return {'item_id': item_id}

#Ограничения

ПараметрЗначениеПроверка
ge1item_id >= 1
le1000item_id <= 1000
gt0item_id > 0
lt1001item_id < 1001

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

Запрос /items/0 вернёт:

{ "detail": [ { "type": "greater_than_equal", "loc": ["path", "item_id"], "msg": "Input should be greater than or equal to 1", "input": "0", "ctx": {"ge": 1} } ] }

#Ограничения для строк

from fastapi import FastAPI, Path app = FastAPI() @app.get('/users/{username}') def get_user( username: str = Path( ..., min_length=3, max_length=50, pattern=r'^[a-zA-Z0-9_]+$', # только буквы, цифры, подчёркивание ) ): return {'username': username}

#Ограничения для строк

ПараметрЗначениеПроверка
min_length3Длина строки >= 3
max_length50Длина строки <= 50
patternregexСтрока должна соответствовать шаблону

#Пример pattern

pattern=r'^[a-zA-Z0-9_]+$' означает:

  • ^ — начало строки
  • [a-zA-Z0-9_]+ — одна или более букв (любой регистр), цифр или подчёркивания
  • $ — конец строки

Запрос /users/john_doe123 → OK

Запрос /users/john-doe → Ошибка 422 (дефис не разрешён)

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

@app.get('/users/{user_id}/posts/{post_id}') def get_user_post( user_id: int = Path(..., ge=1), post_id: int = Path(..., ge=1) ): return {'user_id': user_id, 'post_id': post_id}

Запрос /users/5/posts/42 вернёт:

{"user_id": 5, "post_id": 42}

#Порядок параметров

Параметры в пути должны объявляться в том же порядке, в котором они встречаются в URL:

# Правильно: @app.get('/a/{a}/b/{b}/c/{c}') def handler(a: int, b: int, c: int): ... # Неправильно (работает, но запутанно): @app.get('/a/{a}/b/{b}/c/{c}') def handler(c: int, a: int, b: int): ... # Python сопоставит по имени, но это плохой стиль

#Параметры с фиксированными значениями (Enum)

Иногда нужно ограничить набор допустимых значений:

from enum import Enum from fastapi import FastAPI class ModelName(str, Enum): alexnet = "alexnet" resnet = "resnet" squeezenet = "squeezenet" app = FastAPI() @app.get('/models/{model_name}') def get_model(model_name: ModelName): if model_name == ModelName.alexnet: return {"model_name": model_name, "message": "Deep Learning CNN"} if model_name == ModelName.resnet: return {"model_name": model_name, "message": "Residual Network"} return {"model_name": model_name, "message": "Compact Network"}

#Почему str, Enum?

Класс должен наследовать и str, и Enum:

  • str — позволяет FastAPI обрабатывать значение как строку (для URL и JSON)
  • Enum — даёт возможность перечислять допустимые значения

#Что происходит?

  1. FastAPI автоматически генерирует список допустимых значений из Enum
  2. При запросе /models/alexnet значение преобразуется в ModelName.alexnet
  3. В документации Swagger UI будет выпадающий список с вариантами

#Пример ошибки

Запрос /models/vgg вернёт:

{ "detail": [ { "type": "enum", "loc": ["path", "model_name"], "msg": "Input should be 'alexnet', 'resnet' or 'squeezenet'", "input": "vgg", "ctx": {"expected": "'alexnet', 'resnet', 'squeezenet'"} } ] }

#Путь с предопределёнными значениями

Можно комбинировать статические и динамические части:

@app.get('/users/me') def get_current_user(): return {"user_id": "current", "username": "john"} @app.get('/users/{user_id}') def get_user(user_id: int): return {"user_id": user_id}

Важно: Статические маршруты должны объявляться перед динамическими!

FastAPI проверяет маршруты в порядке объявления:

  1. /users/me → точное совпадение
  2. /users/{user_id} → шаблон для остальных

Если поменять порядок, /users/me попадёт в /users/{user_id} и user_id попытается преобразоваться в int из строки "me" → ошибка 422.

#Raw path — путь как есть

Иногда нужно получить весь путь целиком, включая слеши:

from fastapi import FastAPI app = FastAPI() @app.get('/files/{file_path:path}') def get_file(file_path: str): return {"file_path": file_path}

Суффикс :path говорит FastAPI: «захвати всё до конца пути».

Запрос /files/home/user/documents/file.txt вернёт:

{"file_path": "home/user/documents/file.txt"}

Без :path FastAPI попытается сопоставить только первый сегмент (home) и вернёт 404 для остального.

#Пример: API блога

Создадим полноценное API для блога с параметрами пути:

from fastapi import FastAPI, Path from typing import Annotated app = FastAPI(title="Blog API") # Получить статью по ID @app.get('/posts/{post_id}') def get_post( post_id: Annotated[int, Path(..., ge=1, description="ID статьи")] ): return { "post_id": post_id, "title": f"Post {post_id}", "content": "Content here..." } # Получить комментарий по ID поста и ID комментария @app.get('/posts/{post_id}/comments/{comment_id}') def get_comment( post_id: Annotated[int, Path(..., ge=1)], comment_id: Annotated[int, Path(..., ge=1)] ): return { "post_id": post_id, "comment_id": comment_id, "text": f"Comment {comment_id} on post {post_id}" } # Получить пользователя по username @app.get('/users/{username}') def get_user( username: Annotated[str, Path(..., min_length=3, max_length=50, pattern=r'^[a-zA-Z0-9_]+$')] ): return { "username": username, "name": f"User {username}" } # Получить файл по пути @app.get('/files/{file_path:path}') def get_file(file_path: str): return {"file_path": file_path, "content": "..."}

#Отладка параметров пути

#Swagger UI

Откройте /docs и найдите ваш эндпоинт. Вы увидите:

  • Параметры с типами и ограничениями
  • Примеры значений
  • Описание из Path()

Нажмите "Try it out", введите значение → Execute.

Если валидация не пройдёт, увидите детальную ошибку.

#Логирование

Добавьте логирование для отладки:

import logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) @app.get('/items/{item_id}') def get_item(item_id: int = Path(..., ge=1)): logger.debug(f"Received item_id: {item_id}, type: {type(item_id)}") return {'item_id': item_id}

В логах увидите:

DEBUG:__main__:Received item_id: 42, type: <class 'int'>

#Частые ошибки

#Ошибка 1: Несоответствие имён

@app.get('/users/{user_id}') def get_user(uid: int): # Ошибка: имя не совпадает! ...

Проблема: Параметр пути user_id не найден в функции (там uid).

Решение: Имена должны совпадать:

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

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

@app.get('/a/{a}/b/{b}') def handler(b: int, a: int): # Запутанный код ...

Проблема: Python сопоставит по имени, но это сбивает с толку.

Решение: Объявляйте в том же порядке:

@app.get('/a/{a}/b/{b}') def handler(a: int, b: int): ...

#Ошибка 3: Забыли ... в Path()

@app.get('/items/{item_id}') def get_item(item_id: int = Path(ge=1)): # Ошибка: нет обязательного значения ...

Проблема: Без ... или значения по умолчанию FastAPI не поймёт, обязателен ли параметр.

Решение:

@app.get('/items/{item_id}') def get_item(item_id: int = Path(..., ge=1)): ...

#Ошибка 4: Pattern не работает

@app.get('/users/{username}') def get_user(username: str = Path(..., pattern=r'^[a-z]+$')): ...

Запрос /users/John → ошибка, хотя кажется, что подходит.

Проблема: Regex чувствителен к регистру.

Решение:

pattern=r'^[a-zA-Z]+$' # или флаг re.IGNORECASE

#Исполняемая лаборатория

Лаборатория «Каталог товаров с валидацией ID и slug» доступна в публичном GitLab. Она переводит тему в задачу, приближенную к эксплуатации: валидация числовых ID через Path(ge=, le=), slug с pattern, Enum для категории и порядок статических маршрутов перед динамическими.

Склонируйте репозиторий и запустите тесты из его корня:

git clone --branch v1.0 --depth 1 https://gitlab.potapov.me/courses/fastapi_pro.git cd fastapi_pro uv sync --group test uv run --group test pytest path_params/tests

Далее: Query-параметры