システム開発 ホームページ制作

ツイッター インスタグラム メール



【Python】FastAPIの依存性注入

依存性注入(DIパターン)

DIパターンとは、システム開発においてソフトウェア設計のパターンの1つです。クラス、オブジェクトの依存関係を外部から注入します。

例えば、あるクラスAが必要なクラスBのオブジェクトを直接生成して使用してしまうと、クラスBの修正や追加機能が発生した場合にクラスAの修正も行う必要が出てきます。

DIパターンはこのクラス間の依存関係を外部から注入することで、クラスAの修正は不要になります。

また、DIパターンによりテストも容易に実施することが可能です。

FastAPI 依存性注入サンプルコード

from sqlalchemy.orm import Session

from sqlalchemy import Column, Integer, String

from sqlalchemy.ext.declarative import declarative_base

from fastapi import FastAPI, Depends, HTTPException

from contextlib import contextmanager

Base = declarative_base()

# データベース接続用の関数(セッション作成)

@contextmanager

def get_db():

    db: Session = SessionLocal()  # データベースセッションを作成

    try:

        yield db

    finally:

        db.close()  # セッションをクローズ

# サンプルテーブル

class User(Base):

    __tablename__ = 'users'

    id = Column(Integer, primary_key=True, index=True)

    name = Column(String, index=True)

    email = Column(String, unique=True, index=True)

# リポジトリクラス

class UserRepository:

    def __init__(self, db: Session):

        self.db = db

    def create(self, name: str, email: str) -> User:

        db_user = User(name=name, email=email)

        self.db.add(db_user)

        return db_user

    def get_by_id(self, user_id: int) -> User:

        return self.db.query(User).filter(User.id == user_id).first()

    def get_by_email(self, email: str) -> User:

        return self.db.query(User).filter(User.email == email).first()

# サービスクラス(トランザクション管理を含む)

class UserService:

    def __init__(self, user_repository: UserRepository):

        self.user_repository = user_repository

    def create_user(self, db: Session, name: str, email: str) -> User:

        try:

            # 新しいユーザーを作成

            db_user = self.user_repository.create(name, email)

            db.commit()  # トランザクションのコミット

            db.refresh(db_user)  # 作成したユーザー情報をリフレッシュ

            return db_user

        except Exception as e:

            db.rollback()  # エラーが発生した場合はロールバック

            raise HTTPException(status_code=500, detail=f"An error occurred: {e}")

    def get_user_by_id(self, db: Session, user_id: int) -> User:

        return self.user_repository.get_by_id(user_id)

    def get_user_by_email(self, db: Session, email: str) -> User:

        return self.user_repository.get_by_email(email)

app = FastAPI()

# リポジトリを FastAPI の依存関係として設定

def get_user_repository(db: Session = Depends(get_db)) -> UserRepository:

    return UserRepository(db)

# サービスクラスを FastAPI の依存関係として設定

def get_user_service(user_repository: UserRepository = Depends(get_user_repository)) -> UserService:

    return UserService(user_repository)

# エンドポイントでサービスクラスを利用

@app.post("/users/")

def create_user_endpoint(name: str, email: str, db: Session = Depends(get_db), user_service: UserService = Depends(get_user_service)):

    return user_service.create_user(db=db, name=name, email=email)

プログラムの説明

Depends を使った依存性注入 (DI) は、FastAPI の強力な機能で、アプリケーションの各コンポーネントに必要な依存関係を自動的に注入する方法です。このコードでは、Depends を使ってリポジトリやサービスをエンドポイント関数に注入しています。

依存性注入の具体例

1. リポジトリの依存関係注入

def get_user_repository(db: Session = Depends(get_db)) -> UserRepository:
    return UserRepository(db)

  • get_user_repository は、データベースセッション (db: Session) を受け取って、UserRepository のインスタンスを返します。
  • dbDepends(get_db) で、get_db 関数から提供されます。get_db はデータベースセッションを作成し、エンドポイントで使用できるようにします。
  • これにより、UserRepository のインスタンスが FastAPI のエンドポイントで使えるようになります。

2. サービスの依存関係注入

def get_user_service(user_repository: UserRepository = Depends(get_user_repository)) -> UserService:
    return UserService(user_repository)

  • get_user_service は、UserRepository を受け取り、UserService のインスタンスを返します。
  • user_repositoryDepends(get_user_repository) で、先ほど定義した get_user_repository から提供されます。
  • このように、UserService も依存関係として注入されます。

3. エンドポイントでの依存性注入

@app.post("/users/")
def create_user_endpoint(name: str, email: str, db: Session = Depends(get_db), user_service: UserService = Depends(get_user_service)):
    return user_service.create_user(db=db, name=name, email=email)




  • エンドポイント create_user_endpoint では、dbuser_service の依存関係が注入されます。
  • dbDepends(get_db) によってデータベースセッションが提供され、user_serviceDepends(get_user_service) によってサービスクラスが提供されます。

依存性注入の効果

  • 簡潔さ: Depends を使うことで、必要な依存関係を手動で渡す必要がなくなり、コードがシンプルになります。
  • 再利用性: 一度定義した依存関係は他のエンドポイントやクラスでも使い回しができ、コードの重複を避けられます。
  • テストのしやすさ: 依存性注入を使うことで、モックやスタブを使ってテストが容易になります。

結論

Depends は、FastAPI が提供する依存性注入の仕組みで、コンポーネント間の依存関係を自動的に解決し、コードの可読性、再利用性、テストのしやすさを高めます。