今回はFastAPIのRequest BodyのValidationについてです。
【過去記事】
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.基本的なBody関数
from fastapi import Body, FastAPI
app = FastAPI()
@app.post("/items/")
async def create_item(name: str=Body(...), price: float=Body(...)):
return {"name": name, "price": price}
「FastAPIで作るWebアプリ - validation」で述べたようにクエリパラメータの場合はQuery()関数が使われますが、リクエストボディの場合はBody()が用いられます。
(補足2022/07/22)
(...)はPythonの値でEllipsisと呼ばれています。
PydanticとFastAPI において、Ellipsisは値の指定が必須であることを表現するために使われています。
Query Parameters and String Validations
プログラムを起動します。
uvicorn body1:app --reload
以下の正常なデータをRequestします。
curl -X 'POST' 'http://localhost:8000/items/' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"name": "Hanako", "price": 12.5}'
サーバ側は200 okで、クライアント側は以下のメッセージを受け取ります。
{"name":"Hanako","price":12.5}
2.Pydantic modelsでスマートな検証
Pydantic はデータ検証のためのPythonライブラリです。Pythonのtype hintが使われます。
前に取り上げたプログラムを再掲載して、より詳細な説明を加えます。
from fastapi import FastAPI
from typing import Optional
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
@app.post("/items/")
async def create_item(item: Item):
return item
- まずすべての基本となるBaseClassをimportします。
- 次に、それを継承する、われわれのClassであるItemを定義します。Itemの任意のプロパティはtype hintをもちます。これを基にPydanticは送られてきたBodyの検証を行います。
- 最後に引数item のtype hintにItemを指定します。FastAPIはRequestのBodyが型Itemを持っていると知っていて、検証を行います。
以下の正常なデータをRequestします。
curl -X 'POST' 'http://localhost:8000/items/' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"name": "Hanako", "price": 12.5}'
サーバ側は200 okで、クライアント側は以下のメッセージを受け取ります。
{"name":"Hanako","description":null,"price":12.5,"tax":null}
以下のエラーデータをRequestしてみます
curl -X 'POST' 'http://localhost:8000/items/' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"name": "Hanako", "price": "abc"}'
サーバ側は422 Unprocessable Entityを出力し、クライアント側には以下のエラーメッセージを送ります。
{"detail":[{"loc":["body","price"],"msg":"value is not a valid float","type":"type_error.float"}]}
これは個人的には結構スマートな機能だと思います。
今回は以上です。