はい、承知いたしました。FastAPIとORMを使ったデータベース連携の基礎について、約5000語の詳細な解説記事を作成します。
FastAPI ORM 入門:データベース連携の基礎を徹底解説
はじめに
現代のWebアプリケーション開発において、APIは不可欠な要素となっています。特にバックエンドAPIは、フロントエンド(Webブラウザ、モバイルアプリ)や他のサービスとデータをやり取りする重要な役割を担います。そして、ほとんどのWebアプリケーションでは、データを永続的に保存するためにデータベースが必要となります。
PythonでWeb APIを開発するためのフレームワークはいくつか存在しますが、近年注目を集めているのがFastAPIです。FastAPIはその名の通り高速で、モダンなPythonの機能(型ヒント、asyncio)を最大限に活用し、開発効率とパフォーマンスの両立を実現しています。さらに、自動生成されるAPIドキュメント(Swagger UIやReDoc)は開発者体験を大きく向上させます。
FastAPIを使ってAPIを開発する際、データベースとの連携は避けて通れません。しかし、生SQLでデータベース操作を行うのは、コードが煩雑になりやすく、保守性も低下しがちです。そこで登場するのがORM (Object-Relational Mapping) です。ORMは、データベースのテーブルとPythonのオブジェクトをマッピングし、オブジェクト指向的なアプローチでデータベース操作を可能にします。これにより、SQLの知識がなくても、Pythonのコードだけでデータベースを操作できるようになり、開発効率とコードの可読性が向上します。
この記事では、FastAPIとPythonで最も広く使われているORMの一つであるSQLAlchemyを組み合わせ、データベース連携の基礎を徹底的に解説します。具体的には、データベースのセットアップから、SQLAlchemyを使ったモデル定義、FastAPIとSQLAlchemyを連携させるための依存性注入、そしてデータのCRUD(Create, Read, Update, Delete)操作を実装するAPIエンドポイントの構築までを、手を動かしながら学べるように詳細に説明します。
この記事を通じて、以下のことを習得できます。
- FastAPIの基本的な使い方と特徴
- ORMの概念とそのメリット
- SQLAlchemyの基本(Engine, Session, Declarative Models)
- FastAPIとSQLAlchemyを連携させるための依存性注入(Dependency Injection)の活用
- Pydanticを使ったデータの検証と変換
- CRUD操作を実装するFastAPIエンドポイントの構築
- データベースセッションの適切な管理方法
対象読者は、Pythonを使ったWeb開発の経験がある方、またはFastAPIやORMに関心があり、実際にデータベース連携を含むAPIを構築してみたい方です。約5000語に及ぶ詳細な解説を通じて、FastAPIとORMを使ったデータベース連携の基礎をしっかりと身につけ、より実践的なアプリケーション開発に進むための足がかりとすることを目指します。
さあ、FastAPIとSQLAlchemyの強力な組み合わせを使って、データベース連携をマスターしましょう。
1. FastAPIとは
まず、FastAPIについて簡単に振り返りましょう。FastAPIは、Python 3.6+でAPIを構築するためのモダンで高速(高性能)なWebフレームワークです。Starlette(軽量なASGIフレームワーク)とPydantic(データ検証ライブラリ)をベースにして構築されています。
FastAPIの主な特徴は以下の通りです。
- 高性能: Node.jsやGoと同等の高いパフォーマンスを発揮します。これは、ASGI(Asynchronous Server Gateway Interface)上で動作し、非同期処理(
async/await
)をサポートしているためです。 - 高速な開発: 型ヒントを活用することで、エディタの補完機能が強力に働き、エラーの早期発見につながります。また、コード量が少なく済む設計になっています。
- 自動ドキュメント生成: 定義したAPIエンドポイントやデータモデルから、OpenAPI標準に基づいたインタラクティブなAPIドキュメント(Swagger UIとReDoc)が自動生成されます。これは開発者だけでなく、APIを利用するクライアント側にとっても非常に便利です。
- 強力なデータ検証: Pydanticによるデータ検証、シリアライゼーション、デシリアライゼーションが組み込まれています。リクエストボディやクエリパラメータの型チェック、必須項目の検証などを簡単に行えます。
- 依存性注入システム: 複雑な処理やリソース(データベースセッションなど)の取得・管理を効率的に行うための強力な依存性注入システムを備えています。
- 標準準拠: OpenAPI (以前のSwagger) やJSON SchemaといったAPIの標準に準拠しています。
これらの特徴により、FastAPIはAPI開発において非常に生産的かつ保守性の高いフレームワークとして急速に普及しています。
基本的なFastAPIアプリケーションは、以下の要素から構成されます。
FastAPI
インスタンスの作成- HTTPメソッド(GET, POST, PUT, DELETEなど)とパスを指定したルートデコレータ(
@app.get("/")
など) - リクエストを処理するパス操作関数(
async def read_root(): ...
) - 任意で、リクエスト/レスポンスのデータ構造を定義するPydanticモデル
FastAPIを動かすには、ASGIサーバー(Uvicornなど)が必要になります。
“`bash
インストール
pip install fastapi uvicorn
main.py
from fastapi import FastAPI
app = FastAPI()
@app.get(“/”)
async def read_root():
return {“Hello”: “World”}
実行コマンド
uvicorn main:app –reload
“`
このようにシンプルに始めることができます。ここから、データベース連携を組み込んでいきます。
2. ORMとは
ORM (Object-Relational Mapping) は、リレーショナルデータベースとオブジェクト指向プログラミング言語の間で、データの変換を行うための技術またはツールです。簡単に言うと、データベースのテーブルの行をプログラムのオブジェクトとして扱い、オブジェクトの操作を通じてデータベースのデータを操作できるようにする仕組みです。
なぜORMが必要なのでしょうか?
- SQLからの抽象化: ORMを使うと、多くの場合、生SQLを書かずにデータベース操作ができます。代わりに、Pythonのようなオブジェクト指向言語の構文を使ってデータを取得、作成、更新、削除できます。これにより、データベースの種類に依存しないコード(可搬性)を書きやすくなります。
- オブジェクト指向での操作: データベースのレコードをPythonオブジェクトとして扱うことで、オブジェクトの属性としてカラムにアクセスしたり、オブジェクト間の関係(リレーションシップ)をオブジェクトのプロパティとして扱ったりできます。これにより、Pythonコードとの親和性が高まり、コードがより直感的で理解しやすくなります。
- 保守性の向上: SQLクエリがコード中に散らばっていると、変更やデバッグが難しくなりがちです。ORMを使うことで、データベース操作に関するロジックが一元化され、コードの保守性が向上します。
- セキュリティ: ORMの多くは、SQLインジェクションのようなセキュリティリスクを軽減するための仕組み(プリペアドステートメントなど)を内部的に利用しています。
- 生産性の向上: 定型的なSQLクエリを書く手間が省けるため、開発速度が向上します。
Pythonにはいくつかの主要なORMライブラリがあります。
- SQLAlchemy: Pythonで最も人気があり、機能が豊富で強力なORMです。CoreとORMの二つのコンポーネントを持ち、非常に柔軟な使い方が可能です。多くのフレームワークでサポートされています。
- Peewee: シンプルで軽量なORMです。手軽に始めたい場合に適しています。
- Django ORM: Djangoフレームワークに組み込まれているORMです。Djangoを使う場合はこれが一般的です。
この記事では、広く利用されており、FastAPIとの連携実績も豊富なSQLAlchemyを主に取り上げます。SQLAlchemyは、シンプルながらも強力な機能を提供し、小規模なアプリケーションから大規模なエンタープライズアプリケーションまで幅広く対応できます。
3. SQLAlchemy入門
SQLAlchemyは、Pythonにおけるデータベース操作ライブラリであり、ORM機能を提供します。SQLAlchemyは大きく分けて二つのコンポーネントから構成されます。
- SQLAlchemy Core: データベース抽象化レイヤーであり、データベース接続、トランザクション管理、SQLクエリの生成・実行など、低レベルな操作を提供します。PythonコードでSQLクエリをプログラム的に構築できます。
- SQLAlchemy ORM: Coreの上に構築され、データベースのテーブルとPythonクラスをマッピングする機能を提供します。こちらを使うことで、オブジェクト指向的なアプローチでデータベースを操作できます。通常、「SQLAlchemyを使う」と言うとき、特にORMの方を指すことが多いです。
この記事では、主にSQLAlchemy ORMを使ったデータベース連携に焦点を当てます。
SQLAlchemy ORMを使う上で重要な概念は以下の通りです。
- Engine: データベースへの接続を管理します。データベースの種類、接続先、認証情報などを指定して作成します。アプリケーション全体で共有されるべきオブジェクトです。
- Declarative Mapping: データベースのテーブル構造とPythonクラスのマッピングを定義する方法です。クラスの属性としてテーブルのカラムを定義します。
- Base: Declarative Mapping を行う際の基底クラスです。このクラスを継承してORMモデルを定義します。
- Session: データベースとの実際のやり取り(クエリの実行、データの保存、トランザクションなど)を行います。セッションはデータベースに対する作業単位を表し、スコープ(リクエストごとなど)ごとに作成され、使い終わったら閉じられるべきオブジェクトです。
3.1. Engineの作成とデータベース接続
まず、データベースに接続するための Engine
を作成します。Engineはデータベースの接続プールなどを管理し、スレッドセーフです。通常、アプリケーションの起動時に一度だけ作成します。
ここでは、手軽に試せるSQLiteデータベースを例に進めます。SQLiteは単一のファイルとしてデータを保存するため、別途データベースサーバーを用意する必要がありません。
SQLiteへの接続文字列は sqlite:///./test.db
のようになります。sqlite:///
はSQLiteドライバを示し、./test.db
はカレントディレクトリに test.db
という名前でデータベースファイルを作成することを示します。
“`python
database.py (後で全体像で示します)
from sqlalchemy import create_engine
SQLiteデータベースファイルのパス
DATABASE_URL = “sqlite:///./test.db”
Engineを作成
connect_args={“check_same_thread”: False} は
SQLiteがデフォルトで単一スレッド内でのみ接続を許可するため、
FastAPIのようにリクエストごとに異なるスレッドで処理が行われる場合に必要です。
他のデータベース(PostgreSQL, MySQLなど)では不要です。
engine = create_engine(
DATABASE_URL, connect_args={“check_same_thread”: False}
)
“`
create_engine
関数を使ってEngineを作成します。DATABASE_URL
は使用するデータベースに応じて適切な接続文字列を指定します。例えば、PostgreSQLの場合は postgresql://user:password@host:port/dbname
のようになります。
3.2. Sessionの作成と管理
データベースとの実際のやり取りは Session オブジェクトを通じて行います。Sessionは、データベースに対する一連の操作(クエリ、挿入、更新など)を一つのトランザクションとして管理します。データを変更した場合、session.commit()
を呼び出すことでデータベースに永続化され、エラーが発生した場合は session.rollback()
で変更を取り消せます。使い終わったセッションは session.close()
で閉じる必要があります。
SQLAlchemyでは、セッションファクトリを使ってセッションを生成するのが一般的です。sessionmaker
はセッションクラスを生成するためのクラスで、これを使ってカスタマイズしたセッションクラスを作り、そこからセッションインスタンスを作成します。
“`python
database.py (後で全体像で示します)
from sqlalchemy.orm import sessionmaker
SessionLocalクラスを作成
autocommit=False: 自動でコミットしない(手動でcommit()を呼ぶ)
autoflush=False: クエリ実行前に自動でフラッシュしない(パフォーマンス向上のため)
bind=engine: このセッションが使うEngineを指定
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
“`
SessionLocal
は実際のセッションオブジェクト そのもの ではなく、セッションオブジェクトを作成するための ファクトリ です。データベースセッションが必要になったときに、SessionLocal()
を呼び出してセッションインスタンスを取得します。
セッションの管理は非常に重要です。セッションはデータベース接続を保持しているため、使い終わったら必ず閉じなければ、接続リソースをリークさせ、アプリケーションのパフォーマンス低下や障害の原因となります。FastAPIでは、依存性注入システムを利用してセッションを適切に管理するのが一般的なパターンです。これについては後述します。
3.3. ORMモデルの定義
ORMモデルは、データベースのテーブル構造をPythonクラスとして定義したものです。SQLAlchemyでは、declarative_base()
(または新しいスタイルでは DeclarativeBase
)を使って基底クラスを作成し、それを継承してモデルクラスを定義します。
“`python
models.py (後で全体像で示します)
from sqlalchemy import Column, Integer, String, Boolean
from sqlalchemy.ext.declarative import declarative_base # または from sqlalchemy.orm import DeclarativeBase を使用
モデルの基底クラスを作成
新しいバージョンではこちらが推奨
class Base(DeclarativeBase):
pass
古いバージョン(多くのチュートリアルで使われている)はこちら
Base = declarative_base()
Itemテーブルに対応するモデルクラス
class Item(Base):
tablename = “items” # テーブル名を指定
id = Column(Integer, primary_key=True, index=True) # 主キー、インデックス付き
title = Column(String, index=True) # 文字列型、インデックス付き
description = Column(String) # 文字列型
completed = Column(Boolean, default=False) # 真偽値型、デフォルト値あり
“`
Base = declarative_base()
: ORMモデルの基底クラスを作成します。この基底クラスには、テーブル定義に必要なメタデータが格納されます。class Item(Base):
: 基底クラスBase
を継承して、Item
という名前のモデルクラスを定義します。このクラスがitems
テーブルに対応します。__tablename__ = "items"
: このモデルがマッピングするデータベーステーブルの名前を指定します。Column(...)
: テーブルのカラムを定義します。Integer
: 整数型String
: 文字列型 (VARCHAR)Boolean
: 真偽値型
primary_key=True
: そのカラムがテーブルの主キーであることを示します。SQLAlchemyはデフォルトで自動増分(AUTOINCREMENT)を設定します。index=True
: そのカラムにインデックスを作成します。データの検索パフォーマンスを向上させるために使われます。default=...
: カラムのデフォルト値を設定します。
このように、Pythonのクラス定義の中で、テーブル名、カラム名、データ型、制約などを宣言的に定義できます。
3.4. テーブルの作成
定義したモデルに基づいて、データベースに実際のテーブルを作成する必要があります。これは、Base.metadata.create_all()
メソッドを使って行います。このメソッドは、Base
に登録されているすべてのモデルの定義を読み込み、指定されたEngineに対応するデータベース上にテーブルが存在しない場合に限り、テーブルを作成します。
“`python
database.py (後で全体像で示します)
engine, Base, SessionLocal は上記で定義済みとして
def create_tables():
# Baseに登録されている全てのモデルに対応するテーブルを、
# 指定されたengineを使ってデータベースに作成します。
# テーブルが既に存在する場合は何もしません。
Base.metadata.create_all(bind=engine)
アプリケーション起動時にこの関数を呼び出すように設定します。
FastAPIのライフサイクルイベントと連携させます。
“`
この create_tables
関数をFastAPIアプリケーションの起動時に実行するように設定します。
4. データベースの準備
今回はSQLiteを使用するため、特別なデータベースサーバーのインストールは不要です。Pythonに標準で付属している sqlite3
モジュールは、SQLAlchemyが内部的に利用します。
必要なライブラリは以下の通りです。
bash
pip install fastapi uvicorn sqlalchemy pydantic
fastapi
と uvicorn
はFastAPIアプリケーションを実行するために必要です。sqlalchemy
はORM機能を提供します。pydantic
はFastAPIがデータの検証やモデル定義に内部的に利用しますが、ORMモデルとは別にAPIのリクエスト/レスポンスのデータ構造を定義するためにも明示的に利用します。
プロジェクト構造
シンプルなプロジェクト構造を以下のように作成します。
.
├── main.py # FastAPIアプリケーションのエントリポイント
├── database.py # データベース接続設定、Engine, SessionLocal, Base
├── models.py # SQLAlchemy ORMモデル定義
├── schemas.py # Pydanticモデル定義(リクエスト/レスポンスのデータ構造)
└── crud.py # データベース操作(CRUDロジック)
それぞれのファイルにこれまでに説明した内容を記述していきます。
5. FastAPIとSQLAlchemyの連携
FastAPIとSQLAlchemyを連携させるための鍵となるのは、依存性注入 (Dependency Injection) です。FastAPIの依存性注入システムを使うことで、各エンドポイント関数が必要とするデータベースセッションを簡単に、かつ適切に管理して供給できます。
5.1. データベース設定 (database.py
)
まず、データベース接続設定とセッションファクトリを定義するファイルを作成します。
“`python
database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base # SQLAlchemy < 2.0
from sqlalchemy.orm import DeclarativeBase # SQLAlchemy >= 2.0
from sqlalchemy.orm import sessionmaker
SQLiteデータベースファイルのパス。カレントディレクトリに “test.db” を作成します。
DATABASE_URL = “sqlite:///./test.db”
Engineを作成します。
SQLiteの場合、check_same_thread=False が必要です。
engine = create_engine(
DATABASE_URL, connect_args={“check_same_thread”: False}
)
セッションファクトリを作成します。
autocommit=False: 手動でコミット
autoflush=False: 手動でフラッシュ
bind=engine: このセッションファクトリが使用するエンジン
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
ORMモデルの基底クラスを作成します。
SQLAlchemy < 2.0 の場合:
Base = declarative_base()
SQLAlchemy >= 2.0 の場合、こちらを使用し、class Base(DeclarativeBase): pass を models.py に記述することが推奨されます。
しかし、互換性のため、ここでは declarative_base を使用します。
Base = DeclarativeBase()
データベースセッションを取得するためのジェネレーター関数
FastAPIのDependsで利用されます
def get_db():
db = SessionLocal() # 新しいセッションを作成
try:
yield db # セッションを呼び出し元に提供
finally:
db.close() # 呼び出し元の処理が終わったらセッションを閉じる
“`
get_db
関数は、FastAPIの依存性注入システムで利用されるジェネレーター関数です。
db = SessionLocal()
: 新しいデータベースセッションを作成します。yield db
: セッションオブジェクトをFastAPIのエンドポイント関数に提供します。エンドポイント関数はdb
オブジェクトを通じてデータベース操作を行います。finally: db.close()
: エンドポイント関数の処理が終了した後(エラーが発生した場合でも)、finally
ブロックが実行され、db.close()
が呼び出されてデータベースセッションが閉じられます。これにより、セッションのリソースリークを防ぎます。
このパターンは、FastAPIでデータベースセッションを扱う際の標準的な方法です。
5.2. ORMモデルの定義 (models.py
)
データベーステーブルに対応するORMモデルを定義します。
“`python
models.py
from sqlalchemy import Column, Integer, String, Boolean, ForeignKey
from sqlalchemy.orm import relationship
from .database import Base # database.py で定義したBaseをインポート
Itemテーブルに対応するモデル
class Item(Base):
tablename = “items”
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String)
completed = Column(Boolean, default=False)
# 必要に応じて他のテーブルとのリレーションシップを定義
# owner_id = Column(Integer, ForeignKey("users.id"))
# owner = relationship("User", back_populates="items")
“`
ここではシンプルに Item
モデルだけを定義します。Base
は database.py
からインポートします。
5.3. Pydanticモデルの定義 (schemas.py
)
FastAPIはデータの検証とシリアライゼーションにPydanticを利用します。データベースのORMモデルとは別に、APIのリクエストボディやレスポンスのデータ構造をPydanticモデルとして定義するのが一般的です。これにより、APIのインターフェースとデータベースの内部構造を分離できます。
“`python
schemas.py
from pydantic import BaseModel, ConfigDict
データの作成/更新時にクライアントから受け取るデータ構造
class ItemBase(BaseModel):
title: str # タイトルは必須の文字列
description: str | None = None # descriptionはOptionalな文字列(デフォルトはNone)
データ作成時に使用するスキーマ(ItemBaseを継承)
class ItemCreate(ItemBase):
pass # 現時点ではBaseと同じ
データ更新時に使用するスキーマ(ItemBaseを継承)
class ItemUpdate(ItemBase):
completed: bool = False # 完了ステータスも更新可能にする
データベースから取得したデータをクライアントに返す際のデータ構造
ORMモデルのフィールドに加え、IDやデフォルト値が設定されたフィールドを含む
class Item(ItemBase):
id: int # IDはデータベースが生成するため、取得時に必要
completed: bool = False # completedフィールドも取得時に必要
# PydanticモデルがORMモデルと連携するための設定
# データベースから取得したORMインスタンスをPydanticモデルに変換可能にする
# Pydantic v2 以降では ConfigDict(from_attributes=True) を使用
# Pydantic v1.x では class Config: orm_mode = True を使用
model_config = ConfigDict(from_attributes=True)
# class Config:
# orm_mode = True # Pydantic v1.x
“`
ItemBase
:title
とdescription
という、Itemの基本的な属性を定義します。これは、作成、更新、表示など、複数のPydanticモデルで共通するフィールドをまとめるために使います。ItemCreate
: アイテム作成時のリクエストボディの構造を定義します。現在はItemBase
と同じですが、将来的に作成時のみ必要なフィールドが追加された場合などに分離しておくと便利です。ItemUpdate
: アイテム更新時のリクエストボディの構造を定義します。更新可能なフィールド(ここではcompleted
を追加)を含めます。Item
: データベースから取得したItem
ORMモデルのインスタンスを、クライアントに返すJSONレスポンスの形に変換するためのスキーマです。データベースによって生成されるid
やデフォルト値を持つcompleted
フィールドを含めます。model_config = ConfigDict(from_attributes=True)
(またはclass Config: orm_mode = True
): この設定により、PydanticモデルはORMモデルのインスタンスからデータを読み取れるようになります。例えば、SQLAlchemyのItem
インスタンスがあるとき、schemas.Item.model_validate(db_item)
(Pydantic v2) やschemas.Item.from_orm(db_item)
(Pydantic v1.x) のようにして、ORMインスタンスの属性値からPydanticモデルのインスタンスを生成できます。FastAPIはレスポンスモデルを指定するとこの変換を自動で行ってくれます。
5.4. CRUD操作の実装 (crud.py
)
データベースに対する実際の操作(CRUD)を行う関数を定義します。これらの関数はデータベースセッションオブジェクトを受け取り、そのセッションを使ってORMモデルに対する操作を行います。
“`python
crud.py
from sqlalchemy.orm import Session
from . import models, schemas # . を付けてmodels.py, schemas.pyをインポート
アイテムをIDで取得
def get_item(db: Session, item_id: int):
# セッションのqueryメソッドを使って、Itemモデルからidがitem_idのレコードを検索し、最初の1件を取得
# .first() は結果がなければNoneを返す
return db.query(models.Item).filter(models.Item.id == item_id).first()
全てのアイテムを取得(スキップと制限付きで)
def get_items(db: Session, skip: int = 0, limit: int = 100):
# セッションのqueryメソッドを使って、Itemモデルから全てのレコードを取得
# .offset(skip): 指定した数のレコードをスキップ
# .limit(limit): 指定した数のレコードに制限
# .all(): 結果をリストとして取得
return db.query(models.Item).offset(skip).limit(limit).all()
アイテムを作成
def create_item(db: Session, item: schemas.ItemCreate):
# Pydanticモデルのデータを使ってORMモデルのインスタンスを作成
# item.model_dump() は Pydantic v2 の記法。Pydantic v1.x では item.dict()
db_item = models.Item(item.model_dump()) # Pydantic v2
# db_item = models.Item(item.dict()) # Pydantic v1.x
db.add(db_item) # セッションに新しいオブジェクトを追加(データベースへの追加を予約)
db.commit() # データベースにコミット(変更を確定)
db.refresh(db_item) # コミット後にデータベースで生成された値(例: ID)を取得するためにオブジェクトをリフレッシュ
return db_item # 作成したORMインスタンスを返す
アイテムを更新
def update_item(db: Session, item_id: int, item: schemas.ItemUpdate):
db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
if db_item:
# PydanticモデルのデータをORMインスタンスにコピー
# model_dump(exclude_unset=True) は Pydantic v2 の記法。
# exclude_unset=True により、リクエストで送信されなかった(unsetな)フィールドは更新しない
update_data = item.model_dump(exclude_unset=True) # Pydantic v2
# update_data = item.dict(exclude_unset=True) # Pydantic v1.x
for field, value in update_data.items():
setattr(db_item, field, value) # ORMインスタンスの属性を更新
db.add(db_item) # 変更をセッションに追加(ORMが差分を検知)
db.commit() # コミット
db.refresh(db_item) # リフレッシュ
return db_item
return None # 対象が見つからなかった場合
アイテムを削除
def delete_item(db: Session, item_id: int):
db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
if db_item:
db.delete(db_item) # セッションからオブジェクトを削除(データベースからの削除を予約)
db.commit() # コミット
# 削除されたオブジェクトは返せないため、Noneや成功を示す値を返すのが一般的
return {“ok”: True}
return None # 対象が見つからなかった場合
“`
各CRUD関数は、第一引数として db: Session
を受け取ります。これはFastAPIの依存性注入によって提供されます。
get_item
,get_items
: データベースからデータを読み取るクエリを実行します。.query(models.Item)
でItem
モデルに対するクエリビルダを取得し、.filter(...)
で条件を指定、.first()
で最初の1件、.all()
で全ての件数を取得します。create_item
: Pydanticモデルのデータを使ってORMモデルのインスタンスを作成し、db.add()
でセッションに追加、db.commit()
でデータベースに保存、db.refresh()
で最新の状態を読み込みます。update_item
: 対象のアイテムを取得し、Pydanticモデルのデータで属性を更新、db.add()
(変更検知のために明示的に呼ぶ必要はない場合が多いが、慣習として呼ばれることがある)、db.commit()
、db.refresh()
を行います。exclude_unset=True
をPydanticモデルのmodel_dump
(v2) /dict
(v1.x) に指定することで、リクエストボディに含まれていないフィールドは更新対象外にできます。delete_item
: 対象のアイテムを取得し、db.delete()
でセッションから削除、db.commit()
でデータベースから削除します。
これらの関数は、データベース操作の具体的なロジックをカプセル化し、APIエンドポイントから呼び出して利用します。
5.5. FastAPIアプリケーション本体 (main.py
)
FastAPIアプリケーションのエントリポイントとなるファイルを記述します。ここで、アプリケーションインスタンスの作成、データベーステーブルの作成、APIエンドポイントの定義を行います。
“`python
main.py
from fastapi import FastAPI, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List
ローカルモジュールから必要なものをインポート
. を付けて相対インポート
from . import crud, models, schemas
from .database import SessionLocal, engine, create_tables, get_db
FastAPIアプリケーションインスタンスを作成
app = FastAPI()
アプリケーション起動時にデータベーステーブルを作成する
FastAPI < 0.95.0 の場合: @app.on_event(“startup”)
FastAPI >= 0.95.0 の場合: lifespan (非同期処理にも対応) が推奨
ここでは簡単のため on_event を使用しますが、プロダクションでは lifespan を検討してください。
lifespan を使う場合は contextlib.asynccontextmanager を使う必要があり、少し複雑になります。
@app.on_event(“startup”)
def on_startup():
print(“アプリケーション起動中…”)
create_tables() # database.py で定義したテーブル作成関数を呼び出し
print(“データベーステーブル作成完了(または既に存在)”)
— APIエンドポイント定義 —
アイテムを作成するエンドポイント (POST)
リクエストボディは schemas.ItemCreate で検証される
レスポンスは schemas.Item の形式で返される
Depends(get_db) により、get_db関数が実行され、返されたdbセッションがdb引数に渡される
@app.post(“/items/”, response_model=schemas.Item, status_code=status.HTTP_201_CREATED)
def create_item(item: schemas.ItemCreate, db: Session = Depends(get_db)):
# crud関数を呼び出してアイテムを作成
# 例外処理はcrud関数内で行っても良いし、ここでHTTPExceptionを発生させても良い
return crud.create_item(db=db, item=item)
全てのアイテムを取得するエンドポイント (GET)
response_model=List[schemas.Item] で、schemas.Itemのリストが返されることを示す
@app.get(“/items/”, response_model=List[schemas.Item])
def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
# クエリパラメータ skip, limit を受け取り、crud関数に渡す
items = crud.get_items(db, skip=skip, limit=limit)
return items
特定のアイテムをIDで取得するエンドポイント (GET)
{item_id} はパスパラメータ
@app.get(“/items/{item_id}”, response_model=schemas.Item)
def read_item(item_id: int, db: Session = Depends(get_db)):
# パスパラメータ item_id を受け取り、crud関数に渡す
db_item = crud.get_item(db, item_id=item_id)
# アイテムが見つからなかった場合は404エラーを返す
if db_item is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=”Item not found”)
return db_item
特定のアイテムを更新するエンドポイント (PUT)
@app.put(“/items/{item_id}”, response_model=schemas.Item)
def update_item(item_id: int, item: schemas.ItemUpdate, db: Session = Depends(get_db)):
db_item = crud.update_item(db, item_id=item_id, item=item)
if db_item is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=”Item not found”)
return db_item
特定のアイテムを削除するエンドpoint (DELETE)
削除成功時は空のレスポンス(ステータスコード204 No Content)や、成功を示すメッセージを返すことが多い
ここではシンプルに成功を示すdictを返すresponse_modelなしの例とする
@app.delete(“/items/{item_id}”)
def delete_item(item_id: int, db: Session = Depends(get_db)):
result = crud.delete_item(db, item_id=item_id)
if result is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=”Item not found”)
# 削除成功時は通常200 OKまたは204 No Contentを返す
# 戻り値がある場合は200 OKが適切
return result # {“ok”: True} が返される
“`
app = FastAPI()
: FastAPIアプリケーションのインスタンスを作成します。@app.on_event("startup")
: アプリケーションが起動する際に実行されるイベントハンドラを定義します。ここではcreate_tables()
を呼び出し、データベーステーブルが確実に存在するようにします。@app.post("/items/", ...)
など: HTTPメソッド(POST, GET, PUT, DELETE)とURLパスを指定して、APIエンドポイントを定義します。response_model=schemas.Item
: このエンドポイントからのレスポンスデータがschemas.Item
の構造であることを宣言します。FastAPIは、返されるORMインスタンスを自動的にこのPydanticモデルに変換してJSONレスポンスを生成します。status_code=status.HTTP_201_CREATED
: 成功時のHTTPステータスコードを指定します。POSTリクエストでリソースを作成した場合は201 Createdを返すのが慣習です。item: schemas.ItemCreate
: リクエストボディを受け取る引数を定義します。FastAPIは受信したJSONデータをschemas.ItemCreate
Pydanticモデルで検証し、変換してこの引数に渡します。db: Session = Depends(get_db)
: ここがFastAPIの依存性注入の強力な部分です。Depends(get_db)
を指定することで、FastAPIはリクエストが来るたびにget_db
ジェネレーター関数を実行し、yield
されたデータベースセッションオブジェクトをdb
引数に渡します。リクエスト処理が終わると、ジェネレーターのfinally
ブロックが実行され、セッションが閉じられます。これにより、開発者は各エンドポイント関数内でセッションの作成やクローズを気にすることなく、db
オブジェクトを使ってデータベース操作に集中できます。skip: int = 0, limit: int = 100
: クエリパラメータを定義します。デフォルト値を指定することで、パラメータが指定されなかった場合の振る舞いを制御できます。item_id: int
: パスパラメータを定義します。URLパスの一部として渡される値を引数として受け取ります。HTTPException
: エラーが発生した場合にクライアントにHTTPエラーレスポンスを返すために使用します。例えば、指定されたIDのリソースが見つからなかった場合にstatus.HTTP_404_NOT_FOUND
を返します。
この main.py
ファイルを実行可能なFastAPIアプリケーションとして、UvicornなどのASGIサーバーで起動します。
bash
uvicorn main:app --reload
--reload
オプションを付けると、コードの変更が自動的に検知され、サーバーが再起動します。
サーバーが起動したら、ブラウザで http://127.0.0.1:8000/docs
にアクセスしてみてください。FastAPIが自動生成したSwagger UIが表示され、定義したAPIエンドポイントを試すことができます。
6. 実践的なCRUD APIの構築
これまでに定義したファイルを使って、実際にCRUD操作のエンドポイントを試してみましょう。
6.1. データの作成 (POST)
POST /items/
エンドポイントを使って、新しいアイテムを作成します。
リクエスト (例):
json
{
"title": "Buy groceries",
"description": "Milk, Bread, Eggs"
}
FastAPIはリクエストボディのJSONを schemas.ItemCreate
モデルで検証します。問題なければ、そのデータが create_item
関数の item
引数に渡されます。
関数内で crud.create_item(db=db, item=item)
が呼ばれ、データベースに新しいレコードが挿入されます。成功すると、挿入されたアイテム情報(IDを含む)が schemas.Item
の形式で返されます。
レスポンス (例):
json
{
"id": 1,
"title": "Buy groceries",
"description": "Milk, Bread, Eggs",
"completed": false
}
status_code=201
が返されます。
6.2. データの読み取り (GET)
-
全件取得:
GET /items/
エンドポイントにアクセスします。クエリパラメータskip
やlimit
を指定することで、ページネーションのような振る舞いを実現できます。リクエスト:
GET /items/?skip=0&limit=10
(またはGET /items/
でデフォルト値を使用)read_items
関数が実行され、crud.get_items(db, skip=skip, limit=limit)
が呼ばれてデータベースからアイテムのリストが取得されます。取得されたORMインスタンスのリストは、response_model=List[schemas.Item]
の指定により、FastAPIによってschemas.Item
のリストに変換されて返されます。レスポンス (例):
json
[
{
"id": 1,
"title": "Buy groceries",
"description": "Milk, Bread, Eggs",
"completed": false
},
{
"id": 2,
"title": "Learn FastAPI",
"description": "Read documentation and tutorials",
"completed": true
}
// ... 他のアイテム
]status_code=200
が返されます。 -
単一レコード取得:
GET /items/{item_id}
エンドポイントにアクセスします。パスパラメータとして取得したいアイテムのIDを指定します。リクエスト (例):
GET /items/1
read_item
関数が実行され、パスパラメータitem_id
が引数に渡されます。crud.get_item(db, item_id=item_id)
が呼ばれてデータベースから特定のアイテムが取得されます。- アイテムが見つかった場合: 取得されたORMインスタンスが
schemas.Item
に変換されて返されます。 - アイテムが見つからなかった場合:
crud.get_item
はNone
を返します。read_item
関数内のif db_item is None:
の条件が真となり、HTTPException(status_code=404, detail="Item not found")
が発生します。FastAPIはこれを捕捉し、適切なHTTP 404 Not Found レスポンスを生成して返します。
レスポンス (例 – 成功):
json
{
"id": 1,
"title": "Buy groceries",
"description": "Milk, Bread, Eggs",
"completed": false
}status_code=200
が返されます。レスポンス (例 – 失敗):
json
{
"detail": "Item not found"
}status_code=404
が返されます。 - アイテムが見つかった場合: 取得されたORMインスタンスが
6.3. データの更新 (PUT)
PUT /items/{item_id}
エンドポイントを使って、特定のアイテムを更新します。パスパラメータで更新対象のIDを指定し、リクエストボディで更新したいフィールドの値を指定します。
リクエスト (例): PUT /items/1
json
{
"title": "Buy groceries and more",
"completed": true
}
update_item
関数が実行され、パスパラメータ item_id
とリクエストボディ(schemas.ItemUpdate
で検証・変換済み)が引数に渡されます。crud.update_item(db, item_id=item_id, item=item)
が呼ばれ、対象アイテムのデータが更新されます。
- アイテムが見つかった場合: 更新されたORMインスタンスが
schemas.Item
に変換されて返されます。 - アイテムが見つからなかった場合:
HTTPException(status_code=404, detail="Item not found")
が発生します。
レスポンス (例 – 成功):
json
{
"id": 1,
"title": "Buy groceries and more",
"description": "Milk, Bread, Eggs", # descriptionはリクエストに含まれていないため変更されない (exclude_unset=Trueのおかげ)
"completed": true
}
status_code=200
が返されます。
6.4. データの削除 (DELETE)
DELETE /items/{item_id}
エンドポイントを使って、特定のアイテムを削除します。パスパラメータで削除対象のIDを指定します。
リクエスト (例): DELETE /items/1
delete_item
関数が実行され、パスパラメータ item_id
が引数に渡されます。crud.delete_item(db, item_id=item_id)
が呼ばれ、対象アイテムが削除されます。
- アイテムが見つかった場合:
{"ok": True}
という辞書が返されます。 - アイテムが見つからなかった場合:
HTTPException(status_code=404, detail="Item not found")
が発生します。
レスポンス (例 – 成功):
json
{
"ok": true
}
status_code=200
が返されます。(通常、削除成功時は204 No Contentでボディなしを返すことが多いですが、ここではシンプルに{"ok": True}
を返しています)
このように、FastAPIのパス操作関数、Pydanticモデル、そしてSQLAlchemyのORM操作を分離したCRUD関数を組み合わせることで、クリーンで保守性の高いAPIエンドポイントを構築できます。依存性注入によってデータベースセッション管理が自動化されているため、各エンドポイント関数はデータベース操作のロジックに集中できます。
7. エラーハンドリング
データベース操作においては様々なエラーが発生する可能性があります。例えば、一意制約違反、外部キー制約違反、存在しないデータの操作などが考えられます。また、アプリケーションレベルでは、要求されたリソースが見つからない、といったエラーも考慮する必要があります。
FastAPIでは、HTTPExceptionを使うことで、標準的なHTTPエラーレスポンスをクライアントに返すことができます。前述の例では、read_item
, update_item
, delete_item
関数内で、対象のアイテムが見つからなかった場合に HTTPException(status_code=404)
を発生させています。
SQLAlchemyの操作中に発生するデータベース関連のエラーについては、crud.py
の中で適切に処理するか、より上位のレイヤー(APIエンドポイント関数やカスタム例外ハンドラ)で捕捉して対応する必要があります。
例えば、一意制約を持つカラムに重複した値を挿入しようとした場合、SQLAlchemyは IntegrityError
を発生させます。このようなエラーを捕捉し、クライアントに400 Bad Requestなどの適切なエラーコードと共にエラーメッセージを返すことができます。
crud.py
の create_item
関数で一意制約違反を捕捉する例:
“`python
crud.py (一部変更)
from sqlalchemy.exc import IntegrityError # IntegrityErrorをインポート
def create_item(db: Session, item: schemas.ItemCreate):
db_item = models.Item(item.model_dump()) # Pydantic v2
# db_item = models.Item(item.dict()) # Pydantic v1.x
try:
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
except IntegrityError:
# エラーが発生したらロールバック
db.rollback()
# エラーを伝えるために例外を再発生させるか、エラーを示す値を返す
# ここではFastAPI側で捕捉しやすいように独自の例外を発生させるか、Noneなどを返す
# 例外を発生させる場合は、main.pyで捕捉してHTTPExceptionに変換する必要がある
# シンプルにNoneを返す例:
return None
# より堅牢にするなら、main.pyで捕捉するためのカスタム例外を定義する
# raise ItemAlreadyExistsError(“Item with this title already exists”)
“`
そして、main.py
の create_item
エンドポイントでこのエラーを捕捉する例:
“`python
main.py (create_item関数の一部変更)
@app.post(“/items/”, response_model=schemas.Item, status_code=status.HTTP_201_CREATED)
def create_item(item: schemas.ItemCreate, db: Session = Depends(get_db)):
db_item = crud.create_item(db=db, item=item)
if db_item is None: # crud関数がNoneを返した場合(一意制約違反など)
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=”Item with this title already exists”)
return db_item
“`
このように、CRUD関数内で発生しうるデータベースエラーを処理し、それをAPIエンドポイントで捕捉して適切なHTTPExceptionに変換することで、クライアントに対して分かりやすいエラーメッセージとステータスコードを返すことができます。
また、database.py
で定義した get_db
ジェネレーター関数内の try...finally
ブロックは、セッションのクローズを保証するために非常に重要です。APIエンドポイント関数内でどのような例外が発生しても、finally
ブロックが実行され、データベース接続が正しく解放されます。より複雑なトランザクション管理を行う場合は、try...except...finally
を適切に利用し、エラー発生時には db.rollback()
を呼び出すように get_db
関数を修正することも考えられますが、シンプルなCRUD操作では現在の形でも十分な場合が多いです。
8. テスト (基礎)
構築したAPIが期待通りに動作するか確認するためにテストを書くことは重要です。FastAPIはテストがしやすい設計になっており、fastapi.testclient.TestClient
を使うことで、実際にUvicornサーバーを起動することなく、アプリケーションに対するリクエストをシミュレートできます。
ただし、データベース連携を含むAPIのテストは少し複雑になります。テストを実行するたびにデータベースの状態がクリーンである必要があるため、テスト用のインメモリデータベース(SQLite)を使用したり、テストの前後でデータベースをリセットしたりするなどの工夫が必要です。
ここでは、TestClient
を使った簡単なテストの構造だけを示します。テスト用のデータベース設定や、テストの実行方法については、本格的な内容になるため詳細は割愛します。
“`python
test_main.py
from fastapi.testclient import TestClient
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from .main import app # FastAPIアプリケーション本体
from .database import Base # データベースのBase
必要に応じてmodels, schemasなどもインポート
テスト用データベース設定
インメモリSQLiteデータベースを使用
TEST_DATABASE_URL = “sqlite:///./test_temp.db” # ファイルとして作成し、テストごとに削除/再作成することも可能
テスト用EngineとSessionLocalを作成
check_same_thread=False は必要
engine = create_engine(TEST_DATABASE_URL, connect_args={“check_same_thread”: False})
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
テスト用のget_db依存性関数をオーバーライド
テスト中は通常のget_dbではなくこちらが呼ばれる
def override_get_db():
db = TestingSessionLocal()
try:
yield db
finally:
db.close()
テスト前に毎回実行されるフィクスチャ (pytest)
データベーステーブルを全て削除し、再作成する
@pytest.fixture(scope=”function”) # 各テスト関数ごとに実行
def setup_database():
Base.metadata.drop_all(bind=engine) # 全テーブル削除
Base.metadata.create_all(bind=engine) # 全テーブル作成
yield # テスト実行
# Base.metadata.drop_all(bind=engine) # テスト後にも削除する場合はここに記述
TestClientを作成し、依存性注入をオーバーライドする
with TestClient(app) as client: 構文を使うと、テスト終了時にクライアントが自動的に閉じられる
client = TestClient(app)
main.py の get_db 依存性を override_get_db に置き換える
これにより、テスト中はテスト用データベースが使用される
app.dependency_overrides[get_db] = override_get_db
— テスト関数 —
setup_databaseフィクスチャを適用し、データベースをクリーンな状態にしてからテストを実行
def test_create_item(setup_database):
response = client.post(
“/items/”,
json={“title”: “Test Item”, “description”: “This is a test item”}
)
assert response.status_code == 201
data = response.json()
assert data[“title”] == “Test Item”
assert data[“description”] == “This is a test item”
assert “id” in data
assert data[“completed”] == False
def test_read_items(setup_database):
# 事前にアイテムを作成
client.post(“/items/”, json={“title”: “Item 1”, “description”: “Desc 1”})
client.post(“/items/”, json={“title”: “Item 2”, “description”: “Desc 2”})
response = client.get("/items/")
assert response.status_code == 200
data = response.json()
assert len(data) == 2
assert data[0]["title"] == "Item 1"
assert data[1]["title"] == "Item 2"
def test_read_item_not_found(setup_database):
response = client.get(“/items/999”) # 存在しないID
assert response.status_code == 404
assert response.json() == {“detail”: “Item not found”}
他のCRUD操作についても同様にテスト関数を作成
“`
テストを実行するには、pytest
が必要です。
bash
pip install pytest sqlalchemy[sqlite] # sqliteドライバが必要になる場合がある
pytest .
pytest
コマンドを実行すると、カレントディレクトリ以下の test_*.py
または *_test.py
ファイル内のテスト関数(test_*
で始まる関数)が実行されます。setup_database
フィクスチャによって、各テスト実行前にデータベースがリセットされるため、テスト間の干渉を防ぎ、独立したテストを実行できます。
FastAPIの依存性注入システムのおかげで、app.dependency_overrides
を使って get_db
関数をテスト用のデータベースセッションを提供する関数に置き換えるだけで、アプリケーションコードを変更することなくテスト用データベースを使用できます。これは、FastAPIの優れた設計の一つです。
9. 発展的なトピック
この記事ではFastAPIとSQLAlchemyの基本的な連携に焦点を当てましたが、実際のアプリケーション開発ではさらに多くの考慮事項や高度な機能が必要になります。以下に、学ぶべき発展的なトピックをいくつか挙げます。
- 非同期データベース操作: SQLAlchemyは同期/非同期の両方に対応しています。FastAPIは非同期(
async/await
)で動作するため、データベース操作も非同期で行うことで、I/O待ち時間中に他のリクエストを処理できるようになり、アプリケーション全体のパフォーマンスを向上させることができます。SQLAlchemyの非同期対応を使う場合は、asyncio
対応のデータベースドライバ(例:aiosqlite
for SQLite,asyncpg
for PostgreSQL)とcreate_async_engine
,AsyncSession
などを使用する必要があります。 - Alembicを使ったマイグレーション: アプリケーションの開発が進むにつれて、データベースのスキーマ(テーブル構造)は頻繁に変更されます。AlembicはSQLAlchemyと連携してデータベーススキーマの変更履歴(マイグレーションファイル)を管理し、データベースのバージョンアップ・ダウンを自動化するツールです。手動で
create_all
を呼び出すだけではスキーマ変更に対応できないため、本格的なアプリケーション開発にはAlembicが不可欠です。 - リレーションシップ: 実際のデータベースには、複数のテーブルが関連付けられています(一対一、一対多、多対多)。SQLAlchemy ORMは、これらのリレーションシップをPythonモデル間で定義し、関連するオブジェクトを簡単に取得・操作する機能(
relationship
)を提供します。 - より複雑なクエリ: フィルタリング条件の組み合わせ、ソート、グループ化、集計、結合(JOIN)など、より複雑なデータベースクエリが必要になる場合があります。SQLAlchemy ORMのクエリビルダはこれらの高度なクエリもサポートしています。
- トランザクション管理: 複数のデータベース操作をまとめて一つのトランザクションとして扱い、全ての操作が成功するか、一つでも失敗したら全ての変更を取り消す(ロールバック)機能は、データの整合性を保つ上で重要です。SQLAlchemyのSessionはトランザクション管理機能を提供します。
- 設定管理: データベース接続情報などの設定値は、開発環境、テスト環境、本番環境で異なることが一般的です。環境変数や設定ファイルを使って、これらの設定値を安全かつ柔軟に管理する方法を学ぶ必要があります。
- 接続プール: データベース接続の確立はコストのかかる処理です。SQLAlchemyのEngineはデフォルトで接続プールを備えており、接続を再利用することでパフォーマンスを向上させます。設定を調整することで、アプリケーションの負荷に応じた適切な接続プールサイズを設定できます。
- 本番環境へのデプロイ: Docker、Kubernetes、クラウドサービス(AWS, GCP, Azure)など、本番環境にFastAPIアプリケーションをデプロイする方法や、HTTPS化、負荷分散、モニタリングなどの考慮事項も重要です。
これらのトピックは、この記事の基礎を学んだ後に、次のステップとして取り組むべき内容です。
10. まとめ
この記事では、FastAPIとPythonの強力なORMであるSQLAlchemyを組み合わせて、データベース連携を行うための基礎を詳細に解説しました。
- まず、高速でモダンなAPIフレームワークであるFastAPIの特徴を確認しました。
- 次に、データベース操作をオブジェクト指向的に行うためのORMの概念と、そのメリットを理解しました。
- そして、Pythonで最も広く使われているORMの一つであるSQLAlchemyの基本的な使い方(Engine, Session, ORMモデルの定義)を学びました。
- FastAPIとSQLAlchemyを連携させるために、プロジェクト構造を設計し、必要な各ファイル(
database.py
,models.py
,schemas.py
,crud.py
,main.py
)にコードを記述しました。 - 特に、FastAPIの依存性注入システムを活用してデータベースセッションを適切に管理する方法(
Depends
とget_db
ジェネレーター関数)を詳しく解説しました。 - Pydanticモデルを使ってAPIのリクエスト/レスポンスのデータ構造を定義し、ORMモデルとの連携方法(
from_attributes=True
またはorm_mode=True
)を学びました。 crud.py
にデータベース操作のロジックを分離し、APIエンドポイントからこれらの関数を呼び出すことで、CRUD(Create, Read, Update, Delete)操作を実装する方法を具体的に示しました。- APIエンドポイントで発生しうるエラー(例: 対象が見つからない)を
HTTPException
を使ってクライアントに適切に返す方法を学びました。 - 最後に、
TestClient
と依存性注入のオーバーライド機能を使った、データベース連携を含むAPIのテストの基本的な考え方に触れました。
FastAPIとSQLAlchemyの組み合わせは、Pythonで効率的かつ堅牢なWeb APIを開発するための非常に強力な選択肢です。FastAPIのモダンな機能とSQLAlchemyの柔軟で強力なORM機能が組み合わさることで、開発者はデータベース連携を含むバックエンド開発をスムーズに進めることができます。
この記事で解説した内容は、FastAPIとSQLAlchemyを使ったデータベース連携の基礎中の基礎です。実際のプロジェクトでは、ここで紹介した内容に加えて、リレーションシップ、マイグレーション、非同期処理、高度なクエリなど、さらに多くの知識が必要になります。
この記事が、あなたがFastAPIとORMを使ったデータベース連携の世界に足を踏み入れ、次のステップへと進むための確かな基礎となることを願っています。
Happy Coding!