概要
クエリストリングで来る値をどうやってルーティングしバリデーションするか考えます
環境
- Python 3.11.3
- fastapi 0.100.1
- pypdantic 2.1.1
方針
- ルーティングのパラメータでは Action のみバリデーションする
- ルーティング内で Request オブジェクトを参照して Action 名に応じた各種バリデーションをコールする (mode_validate)
上記方針の理由としては BaseModel に Request オブジェクトが渡せないためです
サンプルコード
from enum import Enum
from fastapi import Depends, FastAPI, Query, Request
from fastapi.datastructures import QueryParams
from pydantic import BaseModel, Field, field_validator
app = FastAPI()
# 各種アクション名を管理する列挙型のクラス
class ActionName(Enum):
CREATE_INSTANCE = "CreateInstance"
# CreateInstance(例) という名前のアクションのバリデーションを管理するモデル
class CreateInstance(BaseModel):
instance_name: str = Field(alias="InstanceName")
@field_validator("instance_name")
@classmethod
def validate_instance_name(cls, v: str) -> str:
if v != "ins01":
raise ValueError()
return v
# 起点となる Action 名のバリデーションを管理するモデル
class Action(BaseModel):
action: str = Field(Query(alias="Action"))
@field_validator("action")
@classmethod
def validate_action(cls, v: str) -> str:
# ここでは許可するバリデーション名など基本的なバリデーションのみを行う
if v not in [ActionName.CREATE_INSTANCE.value]:
raise ValueError()
return v
# アクション名に応じて各種バリデーションをコールする
def validate(self, query_params: QueryParams):
if self.action == ActionName.CREATE_INSTANCE.value:
CreateInstance.model_validate(query_params)
@app.get("/")
async def root(request: Request, action: Action = Depends()):
# ルーティングの引数で Request オブジェクトを参照できるのでこれを使って各種アクションのバリデーションをコールする
action.validate(request.query_params)
return action
解説
クエリストリングはキャメルケースで来ることを想定しているので alias プロパティを使ってクエリストリング側のキー名を指定します
BaseModel を使って起点となる Action 名を管理するクラスと Action 名に基づく各種属性を管理するクラスを作成します
モデルクラスは必ず Field を使って定義しましょう、そうしないとうまくバリデーションメソッドがコールされません
Action クラスでは単純な名前のチェックだけを行います
細かいバリデーションはそれぞれで定義したアクション用のクラスを使います
pydantic は V2 を使っているので model_validate や field_validator を使っています
最後に
とりあえずこれをベースに更にデータベースとの連携やバリデーション用のオブジェクトの受け渡しなども考えてみたいと思います
0 件のコメント:
コメントを投稿