JSON
Чтение тела запроса как JSON
.
Описание
JSON (JavaScript Object Notation) (MIME-type: application/json
) — текстовый формат обмена структурированными данными, основанный на JavaScript. Сегодня JSON является языконезависимым и используется в различных языках программирования.
Этот раздел покажет, как извлекать JSON
из тела запроса и валидировать его с помощью Rapidy
.
Типы данных в JSON
Объект
Неупорядоченное множество пар «ключ:значение».
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(),
# or
user_data: UserData = Body(content_type=ContentType.json),
# or
user_data: UserData = Body(content_type='application/json'),
) -> ...:
Отправка с помощью curl
Массив
[
{"username": "User1", "password": "myAwesomePass1"},
{"username": "User2", "password": "myAwesomePass2"}
]
from pydantic import BaseModel
from rapidy.http import post, Body
class UserData(BaseModel):
username: str
password: str
@post('/')
async def handler(
users: list[UserData] = Body(),
) -> ...:
Отправка с помощью curl
Число
Целое или вещественное значение.
Отправка с помощью curl
При отправке строки в формате JSON требуется дополнительное экранирование символов: "111"
Литералы
true
(логическое «истина»), false
(логическое «ложь») и null
(отсутствие значения).
from rapidy.http import post, Body
@post('/')
async def handler(
bool_data: bool = Body(),
) -> ...:
Отправка с помощью curl
Строка
from rapidy.http import post, Body
@post('/')
async def handler(
string_data: str = Body(),
) -> ...:
Отправка с помощью curl
При отправке строки в формате JSON требуется экранирование символов: \"SomeString\"
Кастомный JSON-декодер
По умолчанию Rapidy
использует json.loads
без параметров для декодирования входящего JSON.
Эквивалентные примеры:
илиДля использования кастомного декодера передайте вызываемый объект, принимающий str
, в параметр json_decoder
.
Ожидаемый тип: Callable[[str], Any]
Пример с пользовательским декодером:
Если необходимо использовать json.loads
с параметрами, воспользуйтесь functools.partial
:
import json
from functools import partial
from typing import Any, OrderedDict
from rapidy.http import post, Body
decoder = partial(json.loads, object_pairs_hook=OrderedDict)
@post('/')
async def handler(
data: Any = Body(json_decoder=decoder),
) -> ...:
Извлечение без валидации
Отключение валидации не рекомендуется.
Если валидация отключена, параметр будет содержать данные в том виде, в котором их распаковал JSON-декодер.
Способы отключения валидации
Явное отключение
from pydantic import BaseModel
from rapidy.http import post, Body
class BodyData(BaseModel):
...
@post('/')
async def handler(
data: BodyData = Body(validate=False),
) -> ...:
Использование Any
Отсутствие аннотации типа
Значения по умолчанию
Если HTTP-запрос не содержит тела, параметр получит указанное значение по умолчанию (если оно задано).
Примеры использования
Указано значение по умолчанию
from pydantic import BaseModel
from rapidy.http import post, Body
class BodyData(BaseModel):
...
@post('/')
async def handler(
data: BodyData = Body('some_data'),
# or
data: BodyData = Body(default_factory=lambda: 'some_data'),
) -> ...:
Опциональное тело запроса
from pydantic import BaseModel
from rapidy.http import post, Body
class BodyData(BaseModel):
...
@post('/')
async def handler(
data: BodyData | None = Body(),
# or
data: Optional[BodyData] = Body(),
# or
data: Union[BodyData, None] = Body(),
) -> ...:
Извлечение сырых данных
Rapidy
использует метод json
объекта Request
для получения данных и передает их в Pydantic
для валидации.
Если данные не удастся извлечь как JSON, будет возвращена ошибка ExtractError
:
{
"errors": [
{
"type": "ExtractError",
"loc": [
"body"
],
"msg": "Failed to extract body data as Json: <error_description>"
}
]
}
Как происходит извлечение внутри Rapidy
Rapidy
использует встроенные механизмы aiohttp
Подробнее об объекте aiohttp.Request
и методах извлечения данных можно узнать
здесь.
Однако если параметр аннотирован как bytes
или StreamReader
, данные извлекаются иначе.
Подробнее об объекте StreamReader
можно узнать здесь.
bytes
from rapidy.http import post, Body
@post('/')
async def handler(
user_data: bytes = Body(),
# also you can use pydantic validation
user_data: bytes = Body(min_length=1),
) -> ...:
Внутренний код Rapidy
StreamReader
from rapidy import StreamReader
from rapidy.http import post, Body
@post('/')
async def handler(
user_data: StreamReader = Body(),
) -> ...:
Внутренний код Rapidy
Валидация Pydantic
для StreamReader
не поддерживается.
Невозможно задать значение по умолчанию для StreamReader
.
При попытке установить значение по умолчанию для Body
с аннотацией StreamReader
через default
или
default_factory
будет поднята ошибка ParameterCannotUseDefaultError
.