こんにちは
今回はFastAPIのschemaの考え方を書いていきたいと思います。
FastAPIではpydantic を採用しており、pydanticを利用してschema設定していきます。 今回でいうschemaはDBのschemaではなく、I/Oのリクエスト・レスポンスのschemaの考え方になります。
schemaを考えていくときに押さえていきたいこと
型の設定
昨今、型設定できない開発は開発スピード、不具合の原因、心理的安全性など多方面で良いことがないです。(型に縛られすぎるのも本末転倒なのでほどほどに) そのため、型設定できる方法があるのであれば、導入を考えたい。pythonでは mypy がありますので、mypyを用いて型のチェックをしていきます。
mypyは、プログラムの実行前に型チェックを行います。この型チェックはPythonの型ヒントという記法で書かれた情報をもとにしているので、型ヒントがない場合は、チェックがほぼ行われないので注意が必要です。
$ pip install mypy
box: int = 1 snaqme_price: dict[str, int] = {"box_fee": 1880, "delivery_fee": 330, "discount": 1000} def total_delivery_fee(box: int) -> int: return snaqme_price["delivery_fee"] * box
このような int型やdict型などはさまざまなパターンで肩を決めることが可能です。 mypyに関しては別途詳しく書いていきます
ドメイン
schema管理する上でこのドメインで考えていくことが他の2つより大事だと考えています。 例えば、ユーザー情報を考えていく場合
・ 名前 ・ メールアドレス ・ 住所 ・ 電話番号 ・ 決済情報 ・ 生年月日 ・ 好きなこと ・ 嫌いなこと など
上記のような属性があった場合
ユーザーbase ・ 名前 ユーザー基本情報 ・ メールアドレス ・ 住所 ・ 電話番号 ・ 決済情報 ・ 生年月日 ユーザーの嗜好 ・ 好きなこと ・ 嫌いなこと など
のように分けられるかと思います。
この分け方が絶対と言いたいわけではなく、ユーザー情報という何も考えず一つのスキーマとして管理し続けるとどんな情報が入っているのかぱっと見わからなくなってしまいます。ユーザー情報
としている部分も将来的には分割が必要になり、肥大化されていく予想がつきます。 そのために細かく分けすぎず、大きく分けすぎずが良いと考えています。データベースと違い、FastAPIのレスポンスなどのスキーマは変更しやすいので、気軽にスタートできるのも特徴の一つになります。
レスポンスとリクエストの区別
スキーマとして管理できているがレスポンスとリクエストを根本から分けていくことで開発を進めやすくなると思います。ここで疑問になってくるのが、レスポンスとリクエストに関して同様なスキーマが存在しする場合どうするか?というところです。
私の考えでは無理に共通化させない、レスポンスはレスポンス、リクエストはリクエストと分ける。同様なものを共通化することは大事になってくる部分は多いと思いますが、レスポンスとリクエストに関しては共通化することで動作に不具合が生じさせる一つの原因になりかねない可能性があると考えています。
理由としては、レスポンスとリクエストは思いのほかコンテキストスイッチが発生しうるためです。コンテキストスイッチが発生する時にスキーマを考えていく場合どうしても片方のスキーマの存在を忘れがちになると思います。
なので、極力共通化しなくても良いと考えています。
まとめ
ざっくりではありますが、FastAPIでのschemaの考え方を共有させていただきました。 schemaの考え方に正解は存在しませんが、アンチパターンは存在しています。アンチパータンは開発スピードや心理的安全性を高められないため、アンチパターンが存在していると思っています。 いろんなschemaの考え方があると思いますので、ぜひ、いろんな方のスキーマの考え方を共有してもらえるとありがたく思います。
弊社では 「おやつと、世界を面白く。」 一緒に面白くしたい仲間をお待ちしてます!!