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

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

В то время как параметры пути, запроса и заголовков обычно представляют собой небольшие фрагменты данных, закодированные в URL или заголовках, параметры тела запроса несут основную полезную нагрузку запроса. Они обычно используются в методах как POST, PUT и PATCH, где клиенту необходимо отправить структурированные данные на сервер.

Например:

Это типичный HTTP-запрос с JSON-телом:

POST /users HTTP/1.1
Content-Type: application/json

{
"username": "alice",
"age": 30
}

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

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

  1. Расположение в запросе Параметры тела запроса передаются фундаментально другим способом по сравнению с другими параметрами.

    Давайте еще раз рассмотрим типичный пример POST-запроса:

    POST /submit HTTP/1.1
    Host: example.com
    Content-Type: application/json
    Content-Length: 27

    {"key": "value"}

    Этот HTTP-запрос разделен на две части, разделенные пустой строкой:

    • Строка запроса и заголовки (все до пустой строки): это включает метод (POST), путь (/submit) и заголовки, такие как Content-Type.

    • Тело запроса (все после пустой строки): это содержит фактическую полезную нагрузку, в данном случае JSON-объект.

    В отличие от параметров запроса или пути, параметры тела запроса не появляются в URL или в заголовках. Они размещаются в теле запроса и обычно используются для отправки структурированных данных, таких как JSON, XML или значения, закодированные формой.

  2. Формат кодирования Еще одно ключевое отличие заключается в том, как кодируются параметры тела запроса:

    При отправке параметров запроса кодирование происходит в URL:

    GET /search?query=python&sort=asc

    Значения запроса кодируются URL и относительно ограничены по размеру.

    • Параметры тела запроса, с другой стороны, кодируются на основе заголовка Content-Type. Общие форматы включают:

      • application/json — для отправки JSON-полезных нагрузок.

      • application/x-www-form-urlencoded — часто используется при отправке HTML-форм.

      • multipart/form-data — используется при загрузке файлов.

    Сервер использует заголовок Content-Type, чтобы решить, как разобрать тело запроса. Например, если заголовок application/json, сервер ожидает, что тело будет содержать действительный JSON.

Сводка различий

ОсобенностьПараметры Query/Path/HeaderПараметры Body
Появляется в URL?ДаНет
Местоположение в запросеСтрока запроса или заголовкиПосле пустой строки (тело запроса)
Тип кодированияURL-кодированный (запрос), обычный текстJSON, данные формы, multipart и т.д.
Случай использованияМалые/простые значения, маршрутизацияСложные объекты, формы, загрузка файлов

Понимание этого различия важно при проектировании или использовании API, особенно в типизированных фреймворках, таких как lihil, где параметры тела запроса и другие параметры объявляются по-разному и разбираются с различной логикой под капотом.

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

В lihil есть два способа объявить тело запроса:

Неявное объявление тела запроса через структурированный тип данных

Вы можете просто определить модель тела, используя msgspec.Struct, и lihil автоматически будет рассматривать ее как тело запроса:


import msgspec
from lihil import Route

class CreateUser(msgspec.Struct):
username: str
age: int

user = Route("/users")

@user.post
async def create_user(data: CreateUser) -> str:
return f"Hello {data.username}!"

Это предпочтительный способ, когда тело вашего запроса является структурированным объектом (например, JSON-документом).

начиная с lihil 0.2.9, структурированные типы данных:

  • msgspec.Struct
  • dataclasses.dataclass
  • typing.Typeddict
  • dict

поддерживаются для параметра тела запроса

Явно с Param("body")

Если вы хотите быть явным, или если вы комбинируете данные тела с другими типами параметров, вы можете использовать Param("body"):

from lihil import Param
from typing import Annotated

@user.post
async def create_user(
data: Annotated[CreateUser, Param("body")]
) -> str:
return f"Hello {data.username}!"

Этот подход особенно полезен, когда ваше тело является примитивным значением, таким как строка или список.

Ограничения и валидация

Поскольку параметры тела запроса используют msgspec, вы можете применять ограничения валидации непосредственно в вашем Struct или через Param, точно так же, как вы делали бы с параметрами пути или запроса:

from lihil import Param
from typing import Annotated

class CreateUser(msgspec.Struct):
username: Annotated[str, Param(min_length=3, max_length=30)]
age: Annotated[int, Param(ge=0, le=120)]

Пользовательские декодеры

Для продвинутых случаев использования вы можете предоставить пользовательский декодер через Param:

from lihil import Param
from typing import Annotated

def parse_data(value: bytes) -> CreateUser:
# ваша пользовательская логика
return CreateUser(...)

@user.post
async def create_user(
data: Annotated[CreateUser, Param("body", decoder=parse_data)]
): ...

Это дает вам полный контроль над тем, как интерпретируются сырые байты тела.

Резюме

  • Параметры тела запроса - это мощный способ отправки структурированных данных в HTTP-запросах.

  • Они необходимы для API, которые должны принимать сложные типы данных, такие как JSON-объекты или бинарные файлы.

  • Lihil упрощает работу с параметрами тела запроса, позволяя вам определять их с помощью структурированных типов данных или Param("body").

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