今回はRequest パラメータのバリデーションを取り上げます。パスパラメータとクエリパラメータです。Swagger UIとともに、FastAPIでの開発効率を上げてくれるものです。
【過去記事】
Python Asyncio入門
Aiohttpで作るSimple Web Server - Qiita
Starletteで作る Simple Web Server - QIita
FastAPIで作るWebアプリ - 基本
FastAPIで作るWebアプリ - validation
FastAPIで作るWebアプリ - Body validation
FastAPIで作るWebアプリ - Form validation
1.パスパラメータ
1-1.型チェック
前回と同じプログラムを使います。
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id : int):
return {"item_id": item_id}
起動します
uvicorn path:app --reload
前回はもっぱらSwagger UIからRequestを投げましたが、今回はサーバ側のエラーチェックを確認するためcurlコマンドを使います。
curl http://localhost:8000/items/123
サーバ側のステータス(200 OK)も確認して、クラシアン側に以下のコンテンツが返ってくることも確認します。
{"item_id":123}
今度はエラーデータをRequestします。
curl http://localhost:8000/items/f00
サーバ側のステータス(422 Unprocessable Entity)はエラーとなり、クライアント側にも以下のエラーが返ってきます。型を正しくチェックしているのがわかります。
{"detail":[{"loc":["path","item_id"],"msg":"value is not a valid integer","type":"type_error.integer"}]}
1-2.Enumによる値の制限
Enumを使ってパスパラメータの値を制限することができます。
from enum import Enum
from fastapi import FastAPI
app = FastAPI()
Class Color(str,Enum)
RED = 'red'
GREEN = 'green'
BLUE = 'blue'
@app.get("/items/{color}/{item_id}")
async def read_item(color : Color, item_id : int):
return {"color": color, "item_id": item_id}
ここでEnum classであるColorは親としてstrが必要です。
String-based enum in Python
正しいRequestを投げます
curl http://localhost:8000/items/red/123
サーバ側は200 okで、クライアント側は以下のコンテンツを受け取ります。
{"color":"red","item_id":123}
それでは正しくないRequestを投げます。'black'はEnumには含まれていません。
curl http://localhost:8000/items/black/123
サーバ側は422 Unprocessable Entityとなり、クライアント側は以下のエラーを受け取ります。
{"detail":[{"loc":["path","color"],"msg":"value is not a valid enumeration member; permitted: 'red', 'green', 'blue'","type":"type_error.enum","ctx":{"enum_values":["red","green","blue"]}}]}
ここまでで、如何にvalidationが、Pythonのtype hintの記述で、自然に行われるかがわかります。もっと多くのエラーチェックがありますが、次に進んでいきましょう。
2.クエリパラメータ
以下のようなプログラムを考えます。
from typing import Optional
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: Optional[str] = Query(None, max_length=5)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
Query()関数でより進んだValidationを行うことができます。第一引数にdefault値をとり、第二引数以降にValidationを記述します。Query(None, min_length=3) はデフォルト値がNoneで3文字以上の文字列の値が必要です。デフォルト値を指定せず、値の指定が必須の場合はQuery(..., min_length=3)と書きます。
(補足2022/07/22)
(...)はPythonの値でEllipsisと呼ばれています。
PydanticとFastAPI において、Ellipsisは値の指定が必須であることを表現するために使われています。
Query Parameters and String Validations
それでは正常なRequestを発行してみましょう
curl http://localhost:8000/items/?q=foo
サーバ側に200 okが表示され、クライアント側には以下の値が返ります。
{"items":[{"item_id":"Foo"},{"item_id":"Bar"}],"q":"foo"}
それでは文字列に長さが5を超えるものを指定してみましょう。
curl http://localhost:8000/items/?q=foofoo
サーバ側に422 Unprocessable Entityが表示され、クライアント側に以下のエラーが表示されます。
{"detail":[{"loc":["query","q"],"msg":"ensure this value has at most 5 characters","type":"value_error.any_str.max_length","ctx":{"limit_value":5}}]}
パスパラメータとクエリパラメータのValidationについて見てきましたが、とても簡単です。またここでは十分に取り上げられませんでしたが、とても豊富です。FastAPIの開発効率が良いのも十分理解できます。
Request Bodyについては次回取り上げるつもりです。
今回は以上です。