FastAPIのスキーマクラスをOpenAPIから生成する方法
2022.03.04
PythonでAPIを構築する要件があり、フレームワークに比較的モダンなFastAPIを採用しました。FastAPIはバックエンドの開発を行えば自動でOepnApi定義を生成する機能が備わっていますが、今回はこれを使わず、事前に用意したOepnApi定義からFastAPIで利用するスキーマクラスを生成する方法を紹介します。
OpenAPI定義からFastAPIで利用するスキーマクラスを出力すると何が良いのか?
- OpenAPI定義のみで設計の確認が可能
- FastAPIでクラスを書く必要がなくなる
OpenAPIの準備
FastAPIのソースコードとOpenAPI定義は以下のような構成で準備します。
ちなみに定義ファイルのパスが generated/openapi.json となっているのは、openapi-generatorを利用してopenapi.jsonを生成していて、弊社ではよくこの構成で開発しています。
project
L api
L main.py : FastAPIのmain.py
L schema
L generated
L openapi.json : OpenAPI定義ファイル
datamodel-code-generatorのインストール
OpenAPI定義からschemaクラスを生成するには、datamodel-code-generator
を利用します。以下のコマンドを実行してpython環境にインストールします。
# インストールコマンド
$ pip install datamodel-code-generator
$ datamodel-codegen --version
0.11.19
schemas.pyを出力する
次に、以下のコマンドを実行してスキーマファイルをFastAPIのプロジェクト内に出力します。
datamodel-codegen --input /schema/generated/openapi.json --input-file-type openapi --output api/schemas.py
サンプルとして以下のOpenAPI定義で実行して、このようなpythonのソースコードが生成されました。
schema/generated/openapi.json
{
"openapi" : "3.0.3",
"info" : {
"title" : "api",
"version" : "0.0.1"
},
"servers" : [ {
"url" : "/"
} ],
"tags" : [ {
"description" : "index",
"name" : "index"
} ],
"paths" : {
"/" : {
"post" : {
"description" : "POST",
"operationId" : "IndexPost",
"requestBody" : {
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/IndexPostRequest"
}
}
},
"description" : "POST",
"required" : true
},
"responses" : {
"200" : {
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/IndexPostResponse"
}
}
},
"description" : "OK"
}
},
"tags" : [ "index" ]
}
}
},
"components" : {
"schemas" : {
"IndexPostRequest" : {
"properties" : {
"name" : {
"type" : "string"
}
},
"type" : "object"
},
"IndexPostResponse" : {
"properties" : {
"hello" : {
"type" : "string"
}
},
"type" : "object"
}
}
}
}
api/schemas.py
# generated by datamodel-codegen:
# filename: openapi.json
# timestamp: 2022-02-25T07:02:11+00:00
from __future__ import annotations
from typing import Optional
from pydantic import BaseModel
class IndexPostRequest(BaseModel):
name: Optional[str] = None
class IndexPostResponse(BaseModel):
hello: Optional[str] = None
FastAPIの実装
生成したschemas.pyをFastAPIで実装してみます。api/main.py
を以下のように変更しました。
api/main.py
from FastAPI import FastAPI
from schemas import IndexPostRequest, IndexPostResponse
app = FastAPI()
@app.post("/", response_model=IndexPostResponse)
def read_root(request:IndexPostRequest) -> IndexPostResponse:
response = IndexPostResponse()
response.hello = request.name
return response
動作確認
FastAPIをローカル環境で動かして、以下のコマンドを実行して想定どおりに動いているかを確認します。
$ curl -X 'POST' \
'http://0.0.0.0:8000/' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"name": "World"
}'
{"hello":"World"}
想定した値が返ってきました。
まとめ
OpenAPIはこういったクラス生成ツールが充実していてとても良いですね。