response_modelの使い方について【FastAPI】

FastAPIではリクエストやレスポンスが適切な内容であるかをバリデーションすることができます。

response_modelは名前の通りレスポンスに関する機能で、レスポンスについてバリデーションが行えます。

response_modelの基本

response_modelは下記のコードのように、パスを定義するデコレーターに与えます。
この場合だと、レスポンスは文字列であると指定しています。

from fastapi import FastAPI

app = FastAPI()

@app.get('/', response_model=str)
def index():
    return 'response test'

ちなみにresponse_modelで指定した型以外を返すと、Internal Server Errorが発生してしまいます。

from fastapi import FastAPI

app = FastAPI()

@app.get('/', response_model=str)
def index():
    return 1

# /にアクセスすると
# "GET / HTTP/1.1" 500 Internal Server Error
# とログに出力される。

例としてstrresponse_modelに指定しましたが、多くの場合レスポンスは文字列だけでなく、もっと複雑なはずです。

そのような場合はpydanticやtypingを利用して、複雑な型を用意してやる必要があります。

pydanticはfastapiに付随してインストールされ、typingは標準ライブラリなので、別途インストールは行わなくてOKです。

例えば、コーヒーの情報を返すAPIを作りたいとすると、以下のように型を作成してresponse_modelに使用します。

from fastapi import FastAPI
from pydantic import BaseModel
from typing import List

app = FastAPI()

class CoffeeInfo(BaseModel):
    brand: str
    country: str
    gram: int

# コーヒーの情報を返す
@app.get('/', response_model=CoffeeInfo)
def coffee():
    return {
        'brand': 'blue mountain',
        'country': 'jamaica',
        'gram': 100
    }

# コーヒーの情報を複数返す
@app.get('/multi-coffee', response_model=List[CoffeeInfo])
def multi_coffee():
    coffee1 = {
        'brand': 'blue mountain',
        'country': 'jamaica',
        'gram': 100
    }
    coffee2 = {
        'brand': 'kona',
        'country': 'america',
        'gram': 250
    }

    return [coffee1, coffee2]

要素の切り捨てとデフォルト値

要素の切り捨て

response_modelに指定した型を満たしているが、余計な要素が追加されている場合はどうなるでしょうか?

下記のコードでは、pricecurrencyが余計にreturnされていますが、エラーにはなりません。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class CoffeeInfo(BaseModel):
    brand: str
    country: str
    gram: int

# コーヒーの情報を返す
@app.get('/', response_model=CoffeeInfo)
def coffee():
    return {
        'brand': 'blue mountain',
        'country': 'jamaica',
        'gram': 100,
        'price': 800,
        'currency': 'yen'
    }

では、実際のレスポンスはどうなっているのでしょうか?Swagger UIにアクセスして、レスポンスを確認してみます。

レスポンスにはpricecurrencyは存在していません。このように、response_modelに指定した型を満たしているが、余計な要素がある場合は切り捨てられるようです。

デフォルト値

余計な要素は切り捨てられるようですが、逆に一部が不足している場合にはどうなるでしょうか?

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class CoffeeInfo(BaseModel):
    brand: str
    country: str
    gram: int

# コーヒーの情報を返す
@app.get('/', response_model=CoffeeInfo)
def coffee():
    return {
        'brand': 'blue mountain',
        'country': 'jamaica'
    }

上記のコードをSwagger UIで確認してみると、Internal Server Errorとなっていることがわかります。

では、不足している要素を補うにはどうすれば良いでしょうか?

これはデフォルト値を設定すること可能です。
デフォルト値は、下記のようにして設定することができます。

class CoffeeInfo(BaseModel):
    brand: str
    country: str
    gram: int = 100

デフォルト値を設定して再度アクセスすると、このようにエラーにはならずにデフォルト値を使用したレスポンスが得られています。

response_model_includeとresponse_model_excludeについて

工事中

コメント