Перейти к содержанию

X-WWW-Form-Urlencoded

Чтение тела запроса как application/x-www-form-urlencoded.

Описание

X-WWW-Form-Urlencoded (MIME-type: application/x-www-form-urlencoded) — это распространённый тип контента, используемый для передачи данных через HTML-формы в Интернете.

Формат представляет собой строку с парами ключ-значение в виде: key1=value1&key2=value2.

from pydantic import BaseModel
from rapidy.http import post, Body, ContentType

class UserData(BaseModel):
    username: str
    password: str

@post('/')
async def handler(
    user_data: UserData = Body(content_type=ContentType.x_www_form),
    # or
    user_data: UserData = Body(content_type='application/x-www-form-urlencoded'),
) -> ...:
Отправка с помощью curl
curl -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=User&password=myAwesomePass" \
http://127.0.0.1:8080

Извлечение без валидации

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

Если валидация отключена, параметр будет содержать базовую структуру aiohttp:

  • Body(content_type=ContentType.x_www_form)MultiDictProxy[str]

Способы отключения валидации

Явное отключение

from pydantic import BaseModel
from rapidy.http import post, Body, ContentType

class BodyData(BaseModel):
    ...

@post('/')
async def handler(
    data: BodyData = Body(validate=False, content_type=ContentType.x_www_form),
) -> ...:

Использование Any

@post('/')
async def handler(
    data: Any = Body(content_type=ContentType.x_www_form),
) -> ...:

Отсутствие аннотации типа

@post('/')
async def handler(
    data = Body(content_type=ContentType.x_www_form),
) -> ...:

Значения по умолчанию

Если HTTP-запрос не содержит тела, параметр получит указанное значение по умолчанию (если оно задано).

Примеры использования

Указано значение по умолчанию

from pydantic import BaseModel
from rapidy.http import post, Body, ContentType

class BodyData(BaseModel):
    ...

@post('/')
async def handler(
    data: BodyData = Body('some_data', content_type=ContentType.x_www_form),
    # or
    data: BodyData = Body(default_factory=lambda: 'some_data', content_type=ContentType.x_www_form),
) -> ...:

Опциональное тело запроса

from pydantic import BaseModel

from rapidy.http import post, Body, ContentType

class BodyData(BaseModel):
    ...

@post('/')
async def handler(
    data: BodyData | None = Body(content_type=ContentType.x_www_form),
    # or
    data: Optional[BodyData] = Body(content_type=ContentType.x_www_form),
    # or
    data: Union[BodyData, None] = Body(content_type=ContentType.x_www_form),
) -> ...:

Извлечение сырых данных

Rapidy использует метод post объекта Request для получения данных и передаёт их в Pydantic для валидации.

Как происходит извлечение внутри Rapidy
async def extract_post_data(request: Request) -> Optional[MultiDictProxy[Union[str, bytes, FileField]]]:
    if not request.body_exists:
        return None

    return await request.post()

Rapidy использует встроенные механизмы aiohttp.

Подробнее об объекте aiohttp.Request и методах извлечения данных можно узнать здесь.

x-www-form-urlencoded и multipart/form-data обрабатываются одинаково.

Оба этих типа данных извлекаются через метод post объекта Request, что является особенностью реализации aiohttp.

Однако, если параметр аннотирован как bytes или StreamReader, данные извлекаются иначе.

Подробнее об объекте StreamReader можно узнать здесь.

bytes

@post('/')
async def handler(
    user_data: bytes = Body(content_type=ContentType.x_www_form),
    # also you can use pydantic validation
    user_data: bytes = Body(content_type=ContentType.x_www_form, min_length=1),
) -> ...:
Внутренний код Rapidy
async def extract_body_bytes(request: Request) -> Optional[bytes]:
    if not request.body_exists:
        return None

    return await request.read()

StreamReader

from rapidy import StreamReader

@post('/')
async def handler(
    user_data: StreamReader = Body(content_type=ContentType.x_www_form),
) -> ...:
Внутренний код Rapidy
async def extract_body_stream(request: Request) -> Optional[StreamReader]:
    if not request.body_exists:
        return None

    return request.content

Валидация Pydantic для StreamReader не поддерживается.

Значение по умолчанию для StreamReader задать нельзя.

Если попытаться установить значение по умолчанию для Body с аннотацией StreamReader через default или default_factory, будет вызвана ошибка ParameterCannotUseDefaultError.

from rapidy import StreamReader

@post('/')
async def handler(
    user_data: StreamReader = Body(content_type=ContentType.x_www_form),
) -> ...:
------------------------------
Handler attribute with Type `Body` cannot have a default value.

Handler path: `<full_path>/main.py`
Handler name: `handler`
Attribute name: `data`
------------------------------