この記事の目的
- FastAPIにおける依存性注入についてわかる
- 依存性注入を利用することによるメリットがわかる
- 具体的な実装例を知ることができる
記述しないこと
FastAPIの書き方
依存性注入とは
依存性注入はクラスや関数の引数としてオブジェクトを渡すことで、そのオブジェクトに依存する別のクラスや関数を呼び出すことができるようにするデザインパターンの一つだよ
FastAPIの場合はAPIのエンドポイント関数やビジネスロジックの関数に必要なデータを自動的に提供することができるよ
FastAPIでは、関数に必要なデータを引数として宣言するだけで、FastAPIが自動的に依存関係を解決し、必要なデータを提供してくれるよ
例えば、APIのエンドポイント関数であれば、HTTPリクエスト情報やデータベースコネクションを引数として宣言することができ、FastAPIが自動的にこれらのオブジェクトを生成し、関数に渡してくれるよ
依存性注入によって、アプリケーションのコードがよりスマートでシンプルになり、テスト容易性が向上するというメリットがあるんだよ!
言葉では何いうてるかわからんし実装例見てみよかぁ〜
FastAPIで依存性注入を使用し、MyServiceクラスをインスタンス化する例だよ
from fastapi import Depends, FastAPI
class MyService:
def __init__(self, db: Database):
self.db = db
class Database:
def __init__(self, host: str, port: int):
self.host = host
self.port = port
app = FastAPI()
# Databaseの依存性を定義する
def get_database():
return Database(host="localhost", port=5432)
# MyServiceにDatabaseの依存性を注入する
@app.get("/")
"""
serviceはインスタンス化されたMyServiceオブジェクト
Databaseの依存性はget_database()関数から自動的に解決されるよ
"""
async def root(service: MyService = Depends(get_database)):
pass
MyServiceクラスにDatabaseクラスのインスタンスを注入することで、MyServiceクラス内でデータベースに関する処理を実装することができるよ
たとえばね、データベースからデータを取得することやデータを更新する、削除する、新しいデータを作成するなどの操作が可能になるんだ!
また、依存性注入により、テストの容易性が向上するよ
依存するオブジェクトをモックオブジェクトに置き換えることができるため、単体テストをより簡単に実行できるんだ!
これによりMyServiceクラスの振る舞いをより確実にテストし、品質の高いコードを実現することができるよ
つまり依存性注入のメリットって??
- テスト容易性の向上:依存するオブジェクトをモック化することで、依存先のオブジェクトの振る舞いをコントロールしやすくなり、単体テストが容易になるよ!
- 可読性・保守性の向上:依存関係が明示的に宣言されるため、コードの可読性が向上するよ。また、依存性が分離されることで、コードの保守性が向上するよ!
- 柔軟性の向上:依存先を容易に入れ替えることができるため、アプリケーションの柔軟性が向上するよ。例えば、データベースの実装を変更する際にも、依存性注入を使うことで、変更が容易になるんだ!
- 再利用性の向上:依存関係が明示的に宣言されるため、依存性のあるコンポーネントを他のアプリケーションに再利用することが容易になるよ!
う〜ん、実装例が少ないなぁ。じゃあもう一つ見てみようか!
from typing import Union
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.skip + commons.limit]
response.update({"items": items})
return response
このコードの場合、FastAPIのDependsデコレータを使用して、CommonQueryParamsクラスを依存関係として注入することで、クエリパラメータの値を簡単に取得できるんだ
CommonQueryParamsクラスは、q、skip、limitの3つのパラメータを解析し、それぞれの値をインスタンス変数に割り当てるため、APIの実装を簡素化できるよ
また、DependsデコレータによってFastAPIがクエリパラメータを検証してエラーを返すため、APIの安全性も向上するんだよね
つまりは依存性注入により、このAPIの実装はより明確になり、保守性やテストのしやすさが向上し、コードの品質も改善されるため、依存性注入が行われていると考えられるんだ!