Используйте Pydantic для удобной проверки данных json в теле запроса, а затем передайте проверенный объект экземпляра модели в класс контекста для создания контекста этого запроса. Класс контекста сохраняет исходную версию параметра и запрещает его модификацию (
Код: Выделить всё
raw_params
Код: Выделить всё
curr_params
Текущий статус
Я могу вручную создать экземпляр класса контекста в функции обработки запроса, но де-факто это становится шаблонным кодом (если я хочу, чтобы такое поведение было согласованным в моем проекте), что противоречит философии FastAPI по уменьшению дублирования кода.
ОжиданиеАвтоматически создавать экземпляр класса контекста с помощью механизма Depends, официально предоставляемого FastAPI.
Моя минимальная реализация
Обратите внимание, что этот пример упрощен, чтобы скрыть бизнес-информацию, связанную с конфиденциальностью.
Код: Выделить всё
import copy
from typing import Generic, TypeVar
from uuid import uuid4
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
full_name: str
nickname: str
age: int
class Item(BaseModel):
name: str
price: float
alias: str = ""
brand: str = ""
T = TypeVar("T")
class QueryContext(Generic[T]):
"""to simplify context passing"""
def __init__(self, raw_params: T):
self.request_UUID = uuid4()
self._raw_params = raw_params
self.curr_params = copy.deepcopy(raw_params)
self.extra = {}
return
@property
def raw_params(self):
return self._raw_params
@raw_params.setter
def raw_params(self, *args, **kwargs):
raise AttributeError("Cannot modify raw params! Use `curr_params` instead.")
@app.post("/update_user")
async def update_user(user: User):
ctx = QueryContext(user) # Bad smell
ctx.curr_params.full_name = "new full name"
ctx.curr_params.age += 5
print(
f"request {ctx.request_UUID} done. raw user: {ctx.raw_params} curr params: {ctx.curr_params}"
)
return ctx.curr_params
@app.post("/update_item")
async def update_user(item: Item):
ctx = QueryContext(item) # Bad smell
ctx.curr_params.name = "[HOT] " + ctx.curr_params.name
ctx.curr_params.price = -1
ctx.extra["msg"] = "Has sold out!"
print(
f"request {ctx.request_UUID} done. raw item: {ctx.raw_params} curr params: {ctx.curr_params} extra info: {ctx.extra}"
)
return ctx.curr_params
Подробнее здесь: https://stackoverflow.com/questions/790 ... model-to-v