FastAPI で None の値を null から undefined に変換する
はじめに
こんにちは。@hayata-yamamotoです。
FastAPI をベースにしたバックエンドを運用開発していくにあたり None の使用を伴う API 定義を行うと、None で指定した値が OpenAPI 定義上では Optional の扱いを受けてしまい、TypeScript 側で見ると undefined と見做されるという問題がありました。
今回は、その OpenAPI 定義上の表記と、FastAPI の実際のレスポンスを整合させるために行った設定をご紹介します。
解決方法
FastAPI で response_model_exclude_none
を True で設定すると、 None の値が含まれるキーがレスポンス上に存在しない状況になります。[1]
これは、Pydantic に用意されている dict
メソッドに定義されている exclude_none
[2] を API のレスポンスに対して実行するメソッドで、レスポンスをシリアライズする際に、None で定義されている値を全て除外してくれます。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Article(BaseModel):
id: str
content: str
category: str | None
@app.get("/articles", response_model=list[Article], response_model_exclude_none=True)
def get_articles() -> list[Article]:
return [{"id": "test1", "content": "test", "category": None}]
具体的にどんな問題があったのか?
弊社では、FastAPI を用いてバックエンドシステムを運用し、OpenAPI 定義をやりとりすることでクライアントサイドが常に最新の API 情報を使える状態を作っています。
しかし、以下のような API を定義すると、レスポンスで返却される category の値は実際には null であるにもかかわらず、OpenAPI 定義上の category は Optional な値となり、クライアントサイドから見ると undefined が返却されるように見えてしまいます。Python の型定義では、Optional
は Union[X, None]
か X | None
に相当する型定義であり、バックエンドとしては null になるのが正解な挙動ではあるのですが、クライアントサイドからみると OpenAPI 上の optional 定義が undefined
と解釈されるため、意図せず認識齟齬が発生する事象が起こっていました。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Article(BaseModel):
id: str
content: str
category: str | None
@app.get("/articles", response_model=list[Article])
def get_articles() -> list[Article]:
return [{"id": "test1", "content": "test", "category": None}]
実際に生成される OpenAPI 定義
openapi: 3.0.2
info:
title: FastAPI
version: 0.1.0
paths:
/articles:
get:
summary: Get Articles
operationId: get_articles_articles_get
responses:
"200":
description: Successful Response
content:
application/json:
schema:
title: Response Get Articles Articles Get
type: array
items:
$ref: "#/components/schemas/Article"
components:
schemas:
Article:
title: Article
required:
- id
- content
type: object
properties:
id:
title: Id
type: string
content:
title: Content
type: string
category:
title: Category
type: string
終わりに
今回は、弊社のバックエンドシステムに採用している FastAPI のレスポンスで、None を undefined にして返却する方法をご紹介しました。
もちろん、バックエンドから返却する null を全て undefined にしてしまって問題ないか?は、各チームやプロダクトの特性によって異なります。もし、FastAPI を用いていてかつ、nullish な値を undefined で統一してしまっても問題ない場合はこの方法が有効です。
この記事や弊社に少しでもご興味持っていただけたら、是非カジュアル面談などにお越しください!
Discussion