Перейти к основному содержимому

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

Параметры запроса — это гибкий способ передачи данных на ваш сервер через URL — особенно для таких вещей, как фильтры, пагинация или дополнительные входные данные. Они появляются после ? в URL и состоят из пар ключ-значение.

Как выглядят параметры запроса?

Вот простой запрос с параметрами запроса:

GET /articles?keyword=book&page=2 HTTP/1.1
Host: example.com

В этом примере:

  • keyword — это параметр запроса со значением book.
  • page — это еще один параметр запроса со значением 2.

Эти значения передаются в URL запроса как строки обычного текста. Lihil автоматически обработает разбор и конвертацию типов на основе сигнатуры вашей функции.

Параметры запроса vs другие параметры запроса

  1. Расположение в запросе Параметры запроса кодируются в URL, после параметров пути и начинаются с ?, как часть строки запроса:

    GET /search?query=python&sort=asc HTTP/1.1
  2. Формат кодирования Параметры запроса кодируются URL. Например:

    ?q=hello%20world

    Это означает, что специальные символы (такие как пробелы) процентно-кодируются.

  3. Типы данных Параметры запроса поддерживают:

    • Примитивные типы: str, int, float, bool
    • Массивы/списки: list[str], list[int]

    В отличие от параметров тела, они не могут представлять вложенные структуры, такие как словари. В отличие от параметров пути, параметры запроса могут иметь повторяющиеся ключи (например, tag=python&tag=web).

Объявление параметров запроса в lihil

Вы можете объявлять параметр запроса как неявно, так и явно

Неявное объявление параметра запроса


from lihil import Route

articles = Route("/articles")

@articles.get
async def search(keyword: str, page: int = 1):
...

Если запрос поступает как /articles?keyword=book&page=2, lihil будет:

  • извлекать keyword и page из строки запроса,
  • преобразовывать page в целое число (на основе аннотации типа),
  • передавать оба значения в вашу функцию.
  • Если page не предоставлен, будет использовано значение по умолчанию 1.
  • Если параметр запроса без значения по умолчанию отсутствует или имеет недопустимый тип, который нельзя привести, lihil автоматически ответит ошибкой InvalidRequest.

Явное объявление параметра запроса с Param

Альтернативно, вы можете объявить параметр более явно, комбинируя typing.Annotated и lihil.Param.

@articles.get
async def search(keyword: Annotated[str, Param("query")], page: Annotated[int, Param("query")] = 1):
...

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

В отличие от параметров пути, параметры запроса могут вести себя как двумерные данные. Это означает, что вы можете иметь несколько значений для одного и того же ключа — идеально для массивов или повторяющихся опций:

GET /filter?tag=python&tag=web&tag=backend HTTP/1.1

В lihil вы можете объявить это с типом списка:

from lihil import Route

@Route("/filter")
async def filter_by_tags(tag: list[str]):
...

lihil соберет все значения tag и даст их вам как список.

Для /filter?tag=web&tag=python&tag=backend вы получите ["web", "python", "backend"] как значение tag.

Валидация данных

Для параметров запроса в стиле массива lihil.Param позволяет вам устанавливать ограничения, такие как максимальная длина или валидация элементов.


from lihil import Param

Tags = Param(max_length=5)

@route("/articles")
async def search_articles(tags: Annotated[list[str], Tags]) -> JSONResponse:
...

В этом случае, если запрос включает более 5 тегов, lihil отклонит его с ошибкой 422.

Вы также можете валидировать скалярные параметры запроса таким же образом — например, для установления ограничений диапазона или правил регулярных выражений.


Page = Param(ge=1)

@route("/articles")
async def list_articles(page: Annotated[int, Page]) -> JSONResponse:
...

Пользовательская валидация

Нужен больший контроль? Вы можете определить пользовательский декодер для продвинутой логики валидации. Это работает как для одиночных, так и для основанных на списке параметров запроса.

from lihil import Param, HTTPException

class BlockedTagError(HTTPException[str]):
"This tag is not allowed"

def tag_decoder(value: str) -> str:
if value in {"banned", "spam"}:
raise BlockedTagError(f"Tag '{value}' is blocked")
return value

@route("/filter")
async def filter_tags(tags: Annotated[list[str], Param(decoder=tag_decoder)]) -> JSONResponse:
...

В этом примере, если пользователь пытается фильтровать с заблокированным тегом, таким как "banned" или "spam", lihil поднимет ошибку BlockedTagError. Запрос будет отклонен с ошибкой 422, и сообщение будет указывать, какой тег был заблокирован.

Параметры запроса — это не просто строки ключ-значение — они являются гибкой и мощной частью обработки запросов. С lihil вы получаете конвертацию типов, валидацию и структуру с минимальными усилиями.

Резюме

  • Параметры запроса появляются в URL и идеальны для фильтров, поисковых терминов и пагинации.

  • Они поддерживают как примитивные типы, так и повторяющиеся ключи (списки).

  • В lihil вы можете объявлять их неявно через аннотации типов или явно, используя Param для валидации.

  • Вы можете добавлять ограничения или пользовательские декодеры для надежной валидации ввода.