[Python] FastAPI, Pydantic, SQLAlchemy, Alembicを使ってREST APIを実装する
はい、承知いたしました。提示された構成案に基づき、FastAPI、Pydantic、SQLAlchemy、Alembic を使用したPythonバックエンド入門のZenn記事を執筆します。以下、記事本文です。
【FastAPI 入門】Pythonバックエンド開発の定番構成でCRUD APIを実装しよう
最近、AIを使った処理を含むAPIを使うことが多いのでバックエンドをpythonで構築することが増えてきました。多分こういう人多いと思います。pythonを使ったバックエンド開発では、FastAPIが今アツいですが、まだまだFastAPIに関する日本語の技術記事って少ないです。公式ドキュメント読むのが理想ではありますが、駆け出しエンジニアにとってはある程度情報量を絞って書かれた入門用の記事も有益かと思います。
なので、FastAPIを使おうと思っているエンジニアがスムーズに入門できるように、よくある構成(FastAPI, Pydantic, SQLAlchemy, Alembic)でCRUD(新規作成、取得、更新、削除)を行うREST APIを実装する流れを説明していきたいと思います。ハンズオン形式でやっていくのでぜひ一緒にやってみてください。
前提部分
ここでは、今回の開発環境の構成要素であるFastAPI、Pydantic、SQLAlchemyについて基本的な概要を説明した後、これらを合わせて使うことのメリットについてお話しします。また、今回実装するのはREST APIになりますが、REST APIについても軽く説明しておきます。とはいってもこれらは記事の主旨とはずれるので、さらっと概要だけ説明します。詳細な説明は参考になりそうな記事を掲載しておくのでそちらを参照していただければと思います。
FastAPIって?
FastAPIは、PythonでAPIを構築するためのモダンで高速なWebフレームワークです。Starlette(ASGIフレームワーク)とPydanticに基づいて構築されており、以下の特徴があります。
-
高速: 非同期処理(
async/await
)をサポートしており、高いパフォーマンスを発揮します。 - 高い開発生産性: 型ヒントを最大限に活用することで、コード補完やエラーチェックが行えます。
- 自動ドキュメント生成: OpenAPI標準に基づいたAPIドキュメントを自動生成します。(これがあればフロントエンド側で型定義や呼び出し関数を自動生成できたりします。)
- データバリデーション: Pydanticとの連携により、リクエストデータの自動バリデーションを行います。
Pydanticって?
Pydanticは、Pythonの型ヒントを使用してデータのバリデーションなどを行うライブラリです。Pydanticモデルを定義することで、入力データの型チェックや必須項目の指定、デフォルト値の設定などが容易に行えます。FastAPIはPydanticを深く統合しており、リクエストボディのパースやレスポンスの構築に活用されます。
SQLAlchemyって?
SQLAlchemyは、Pythonので使用できるORM(Object-Relational Mapper)です。データベースとのやり取りを抽象化し、Pythonオブジェクトを使ってデータベース操作を行うことができます。生SQLを書くことなく、Pythonの文法でデータベースを扱えるようになります。
なんでこの構成なの?
FastAPI, Pydantic, SQLAlchemy, Alembic の組み合わせは、Pythonで堅牢なバックエンドAPIを開発する上でとても重要です。
- FastAPI & Pydantic: 高速なAPIの実装、強力なデータバリデーション、自動ドキュメント生成を実現し、API開発の生産性を大幅に向上させます。
- SQLAlchemy: データベース操作を抽象化し、多様なデータベースに対応可能な柔軟性を提供します。
- Alembic: SQLAlchemyと連携してデータベースのスキーマ変更(マイグレーション)を管理します。開発の進捗に合わせてデータベース構造を変更する際に、差分管理やロールバックが容易になります。
これらのライブラリを組み合わせることで、モダンで保守性の高いPythonバックエンドを効率的に構築することができます。
REST APIって?
REST(Representational State Transfer)は、Webサービスの設計原則の集合です。RESTfulなAPIは、リソース(例えば、TODOアイテム)をURIで識別し、HTTPメソッド(GET, POST, PUT, DELETEなど)を使ってそのリソースに対して操作を行います。ステートレスであること、クライアント・サーバ間の分離などが特徴として挙げられます。今回の記事では、このREST原則に則ってAPIを実装します。
- 参考になりそうな記事(後ほど具体的な記事のリンクを追記します)
環境構築
ここでは、上記の構成で開発を行うために環境構築をしていきます。
Poetryを使おう
プロジェクトの依存関係管理には、近年人気が高まっているPoetryを使用します。仮想環境の管理とパッケージ管理を一緒に行える便利なツールです。まだインストールしていない方は、公式ドキュメントを参考にインストールしておきましょう。
プロジェクトディレクトリを作成し、Poetryを初期化します。
mkdir fastapi-todo-app
cd fastapi-todo-app
poetry init
poetry init
を実行すると、対話形式でプロジェクト情報の設定ができます。特にこだわりがなければ Enter を押していけば大丈夫です。最後に pyproject.toml
ファイルが生成されます。
ライブラリを入れよう
必要なライブラリをPoetryを使ってインストールします。
poetry add fastapi uvicorn[standard] sqlalchemy alembic pydantic
-
fastapi
: FastAPI本体 -
uvicorn[standard]
: FastAPIを動かすためのASGIサーバー(Standard版にはwebsocketsなど開発に便利なものが含まれています) -
sqlalchemy
: ORMおよびデータベースツールキット -
alembic
: データベースマイグレーションツール -
pydantic
: データバリデーションライブラリ(FastAPIが内部で利用しますが、明示的に依存関係に含めておきます)
インストールが完了すると、pyproject.toml
に依存関係が追記され、poetry.lock
ファイルが生成されます。また、仮想環境が作成され、そこにライブラリがインストールされます。
作成された仮想環境に入るには以下のコマンドを実行します。
poetry shell
仮想環境から出るには exit
コマンドを使用します。コマンドの先頭に poetry run
をつけることで、仮想環境に入らずにコマンドを実行することも可能です(例: poetry run uvicorn main:app --reload
)。
DBを準備しよう
今回は手軽に進めるためにSQLiteデータベースを使用します。特にインストールは不要で、ファイルとしてデータベースが作成されます。
プロジェクトのルートディレクトリにデータベースファイルを作成することにします。ファイル名は任意ですが、ここでは sql_app.db
とします。これは後ほどSQLAlchemyの設定で指定します。
今回の要件
本記事では、よくあるTODOアプリで最低限必要になりそうなAPIを実装していきます。TODOアプリは入門系の教材で腐るほど見てきたと思います。ちょうど開発に必要な基本的な処理を網羅的に学べる題材なんですよねあれ。便利です。
テーブル設計
TODOアイテムを管理するためのシンプルなテーブルを一つ作成します。
カラム名 | 型 | 制約 | 説明 |
---|---|---|---|
id |
INTEGER | PRIMARY KEY | TODOのID |
title |
TEXT | NOT NULL, UNIQUE | TODOのタイトル |
completed |
BOOLEAN | NOT NULL | 完了しているか |
必要なAPI
以下のCRUD操作に対応するREST APIエンドポイントを実装します。
-
GET
/todos
: TODOの一覧を取得 -
GET
/todos/{todo_id}
: 指定したIDのTODOを取得 -
POST
/todos
: 新しいTODOを作成 -
PUT
/todos/{todo_id}
: 指定したIDのTODOを更新 -
DELETE
/todos/{todo_id}
: 指定したIDのTODOを削除
テーブルを作成しよう
ここから実際に開発に入っていきます。まずはデータベースにテーブルを作っていきましょう。テーブル定義にはSQLAlchemyを、マイグレーションにはAlembicを使用します。
プロジェクトの構造を以下のようにします。
fastapi-todo-app/
├── main.py
├── database.py
├── models.py
└── pyproject.toml
-
main.py
: FastAPIアプリケーションのエントリポイント -
database.py
: データベース接続の設定 -
models.py
: SQLAlchemyのモデル定義
モデルを定義する
models.py
にSQLAlchemyのORMモデルを定義します。
from sqlalchemy import Boolean, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
# データベースの基底クラスを定義
Base = declarative_base()
# TODOアイテムのモデル定義
class Todo(Base):
__tablename__ = "todos" # テーブル名を指定
id = Column(Integer, primary_key=True, index=True) # プライマリキー、インデックス付き
title = Column(String, unique=True, index=True) # タイトル、ユニーク制約、インデックス付き
completed = Column(Boolean, default=False) # 完了フラグ、デフォルト値はFalse
次に、database.py
でデータベースへの接続設定を行います。
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# SQLiteデータベースファイルのパス
SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"
# SQLAlchemyエンジンを作成
# connect_args={"check_same_thread": False} はSQLite使用時の設定
# SQLiteはデフォルトでは単一スレッドしか扱わないため、FastAPIのように複数スレッドでリクエストを扱う場合は必要
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
# データベースセッションクラスを作成
# autocommit=False: トランザクションを手動でコミット
# autoflush=False: セッションに追加したオブジェクトを自動でフラッシュしない
# bind=engine: このセッションがどのエンジンと紐づくか
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
マイグレーションを実行する
データベースのスキーマ管理にはAlembicを使用します。Alembicの初期設定を行います。
まず、Alembicの設定ファイルを作成します。
poetry run alembic init alembic
これにより、alembic
ディレクトリと alembic.ini
ファイルが作成されます。
次に、alembic.ini
を編集して、SQLAlchemyのモデル定義をAlembicに認識させます。alembic.ini
の [alembic]
セクションにある sqlalchemy.url
をデータベース接続URLに設定し、script_location
を alembic
に設定します(これは init
で設定済み)。
# alembic.ini
[alembic]
# ... (他の設定はそのまま)
sqlalchemy.url = sqlite:///./sql_app.db
script_location = alembic
# ... (他の設定はそのまま)
さらに、alembic/env.py
を編集して、SQLAlchemyのBaseメタデータをAlembicに連携させます。
alembic/env.py
を開き、以下の部分を探します。
# target_metadata = None
これをコメントアウトし、代わりに以下を追加します。
# add your model's MetaData object here
# for 'autogenerate' support
from models import Base
target_metadata = Base.metadata
これでAlembicが models.py
の Base.metadata
を参照して、モデル定義からデータベーススキーマの差分を検出できるようになります。
いよいよ、モデル定義に基づいてマイグレーションファイルを作成します。
poetry run alembic revision --autogenerate -m "create todo table"
--autogenerate
オプションを使うと、現在のデータベーススキーマ(最初は存在しないか空)と target_metadata
の定義を比較して、差分を検出してくれます。-m
オプションでマイグレーションに名前をつけることができます。
このコマンドを実行すると、alembic/versions
ディレクトリの中に新しいPythonファイルが作成されます。これがマイグレーションファイルです。ファイル名にはタイムスタンプと指定したメッセージが含まれます。
作成されたマイグレーションファイルの中身を確認してみましょう。upgrade()
関数にテーブル作成の処理、downgrade()
関数にテーブル削除の処理が自動生成されているはずです。
最後に、このマイグレーションをデータベースに適用して、実際にテーブルを作成します。
poetry run alembic upgrade head
head
は最新のマイグレーションを意味します。このコマンドを実行すると、データベースファイル(sql_app.db
)が作成され、その中に todos
テーブルが作成されます。
APIを作ってみよう
次に、APIを実装していきます。実践的な実装を行えるように、デザインパターンに則してきれいなコードを書いていきましょう。
プロジェクトの構造を以下のように変更します。
fastapi-todo-app/
├── main.py
├── database.py
├── models.py
├── schemas.py # Pydanticモデルを定義するファイルを追加
├── crud.py # DB操作を行う関数を定義するファイルを追加
└── pyproject.toml
└── alembic/
-
schemas.py
: リクエストおよびレスポンスのPydanticモデルを定義 -
crud.py
: Create, Read, Update, Deleteといったデータベース操作を担当する関数を定義
デザインパターン(設計ルール)を意識しよう
APIの実装においては、責務を適切に分割することが重要です。今回は簡単な構成ですが、将来的な拡張性や保守性を考慮して、以下の層に分けて考えます。
- APIエンドポイント (main.py): HTTPリクエストを受け付け、リクエストデータのバリデーション、ビジネスロジック層の呼び出し、レスポンスの整形を行います。ここではデータベースとの直接的なやり取りは行いません。
- ビジネスロジック層 (現状はAPIエンドポイント内、またはcrud.pyの一部): アプリケーション固有の処理を行います。今回はシンプルなのでAPIエンドポイントに直接書く部分もありますが、複雑な処理は分離することを検討します。
- データアクセス層 (crud.py): データベースとの直接的なやり取りを担当します。SQLAlchemyを使ったCRUD操作をここに集約します。APIエンドポイントからはこの層の関数を呼び出します。
- スキーマ定義 (schemas.py): Pydanticを使って、リクエストボディやレスポンスデータの構造とバリデーションルールを定義します。
このように層を分けることで、例えばデータベースの種類を変更したり、ビジネスロジックを変更したりする場合に、影響範囲を限定しやすくなります。
まずは、Pydanticモデルを schemas.py
に定義します。
from pydantic import BaseModel, ConfigDict
# TODO作成時のリクエストボディ用スキーマ
class TodoCreate(BaseModel):
title: str
completed: bool = False # デフォルト値を設定
# TODO表示用のスキーマ
class Todo(BaseModel):
id: int
title: str
completed: bool
# SQLAlchemyのモデルと連携するための設定
model_config = ConfigDict(from_attributes=True)
TodoCreate
は新しいTODOを作成する際にクライアントから送られてくるデータを定義します。Todo
はデータベースから取得したTODOデータをクライアントに返す際の形式を定義します。ConfigDict(from_attributes=True)
は、SQLAlchemyモデルのようなORMオブジェクトからPydanticモデルを生成する際に、属性名でマッピングできるようにするための設定です。
次に、データベース操作を行う関数を crud.py
に定義します。
from sqlalchemy.orm import Session
from . import models, schemas
# TODO一覧を取得
def get_todos(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.Todo).offset(skip).limit(limit).all()
# 指定したIDのTODOを取得
def get_todo(db: Session, todo_id: int):
return db.query(models.Todo).filter(models.Todo.id == todo_id).first()
# 新しいTODOを作成
def create_todo(db: Session, todo: schemas.TodoCreate):
# Pydanticモデルのデータを元にSQLAlchemyモデルのインスタンスを作成
db_todo = models.Todo(title=todo.title, completed=todo.completed)
db.add(db_todo) # データベースに追加
db.commit() # トランザクションをコミット
db.refresh(db_todo) # データベースから最新の状態を取得(IDなどが割り当てられる)
return db_todo
# 指定したIDのTODOを更新
def update_todo(db: Session, todo_id: int, todo: schemas.TodoCreate):
db_todo = db.query(models.Todo).filter(models.Todo.id == todo_id).first()
if db_todo is None:
return None
db_todo.title = todo.title
db_todo.completed = todo.completed
db.commit()
db.refresh(db_todo)
return db_todo
# 指定したIDのTODOを削除
def delete_todo(db: Session, todo_id: int):
db_todo = db.query(models.Todo).filter(models.Todo.id == todo_id).first()
if db_todo is None:
return None
db.delete(db_todo)
db.commit()
return db_todo
これらの関数は、データベースセッション(db: Session
)を引数に取り、そのセッションを使ってデータベース操作を行います。
最後に、main.py
にFastAPIアプリケーションとAPIエンドポイントを定義します。データベースセッションの依存性注入もここで行います。
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from . import crud, models, schemas
from .database import SessionLocal, engine
# データベーステーブルが存在しない場合に作成(開発用、Alembicを使う場合は不要だが、手軽な確認のために記述)
# models.Base.metadata.create_all(bind=engine)
app = FastAPI()
# データベースセッションを取得するための依存性
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# TODO一覧取得エンドポイント
@app.get("/todos/", response_model=list[schemas.Todo])
def read_todos(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
todos = crud.get_todos(db, skip=skip, limit=limit)
return todos
# 指定したIDのTODO取得エンドポイント
@app.get("/todos/{todo_id}", response_model=schemas.Todo)
def read_todo(todo_id: int, db: Session = Depends(get_db)):
db_todo = crud.get_todo(db, todo_id=todo_id)
if db_todo is None:
raise HTTPException(status_code=404, detail="Todo not found")
return db_todo
# TODO作成エンドポイント
@app.post("/todos/", response_model=schemas.Todo)
def create_todo(todo: schemas.TodoCreate, db: Session = Depends(get_db)):
# 重複タイトルのチェック(ここでは簡単のためCRUD層ではなくAPI層で実施)
existing_todo = db.query(models.Todo).filter(models.Todo.title == todo.title).first()
if existing_todo:
raise HTTPException(status_code=400, detail="Todo with this title already exists")
return crud.create_todo(db=db, todo=todo)
# 指定したIDのTODO更新エンドポイント
@app.put("/todos/{todo_id}", response_model=schemas.Todo)
def update_todo(todo_id: int, todo: schemas.TodoCreate, db: Session = Depends(get_db)):
db_todo = crud.update_todo(db, todo_id=todo_id, todo=todo)
if db_todo is None:
raise HTTPException(status_code=404, detail="Todo not found")
return db_todo
# 指定したIDのTODO削除エンドポイント
@app.delete("/todos/{todo_id}", response_model=schemas.Todo)
def delete_todo(todo_id: int, db: Session = Depends(get_db)):
db_todo = crud.delete_todo(db, todo_id=todo_id)
if db_todo is None:
raise HTTPException(status_code=404, detail="Todo not found")
return db_todo
get_db
関数は、リクエストごとに新しいデータベースセッションを作成し、処理が完了したらセッションを閉じるための依存性です。FastAPIの Depends
を使うことで、各エンドポイント関数で簡単にデータベースセッションを取得できるようになります。
response_model
にPydanticモデルを指定することで、FastAPIがレスポンスデータを自動的にそのスキーマに沿ってバリデーションおよび整形してくれます。また、自動生成されるAPIドキュメントにも反映されます。
エラーハンドリングとして、指定したTODOが見つからなかった場合に HTTPException
を発生させて404エラーを返すようにしています。
リクエストを送ってみよう
APIを実装したので、実際にリクエストを送って動作を確認してみましょう。まずはUvicornを使ってFastAPIアプリケーションを起動します。
プロジェクトルートディレクトリで以下のコマンドを実行します(仮想環境に入っているか、poetry run
を使うかしてください)。
uvicorn main:app --reload
--reload
オプションをつけると、コードの変更を検出して自動的にサーバーを再起動してくれます。
サーバーが起動したら、ブラウザで http://127.0.0.1:8000/docs
にアクセスしてみてください。FastAPIが自動生成したSwagger UIのAPIドキュメントが表示されるはずです。ここから各APIエンドポイントの仕様を確認したり、実際にリクエストを送ったりすることができます。
ここでは、curlコマンドを使って簡単なリクエスト例を示します。
TODO作成 (POST)
curl -X POST "http://127.0.0.1:8000/todos/" -H "Content-Type: application/json" -d '{"title": "牛乳を買う", "completed": false}'
成功すると、作成されたTODOの情報(IDを含む)がレスポンスとして返ってきます。
TODO一覧取得 (GET)
curl -X GET "http://127.0.0.1:8000/todos/"
作成したTODOのリストが返ってきます。
指定したIDのTODO取得 (GET)
作成したTODOのIDを確認し、そのIDを使ってリクエストします(例: IDが1の場合)。
curl -X GET "http://127.0.0.1:8000/todos/1"
指定したIDのTODO情報が返ってきます。存在しないIDの場合は404エラーになります。
指定したIDのTODO更新 (PUT)
IDが1のTODOを更新する例です。
curl -X PUT "http://127.0.0.1:8000/todos/1" -H "Content-Type: application/json" -d '{"title": "牛乳を買った", "completed": true}'
更新後のTODO情報が返ってきます。
指定したIDのTODO削除 (DELETE)
IDが1のTODOを削除する例です。
curl -X DELETE "http://127.0.0.1:8000/todos/1"
削除されたTODOの情報が返ってきます。その後もう一度GETリクエストをすると404になるはずです。
Swagger UIを使うと、より直感的にAPIのテストができますのでぜひ試してみてください。
リファクタリングをしていこう
最後に、ここまでで書いたコードをきれいにしていきましょう。コードの品質を保つことで、バグが起きた際に「直すべき箇所が明確になる」「修正箇所が少なくて済む」「修正したら他の箇所でバグっちゃった」みたいなことがなくなります。これによって素早くリリースしてどんどん改善を重ねられるアプリを実装することができます。うれしいです。絶対やりましょう。
今回のコードは小規模ですが、それでもいくつか改善できる点があります。
エラー処理を共通化
現在はTODOが見つからなかった場合の404エラーを各APIエンドポイントで個別に HTTPException
としてraiseしています。エラーの種類が増えてきた場合、これを一箇所で管理するとより見通しが良くなります。FastAPIでは、独自の例外ハンドラーを登録することでエラー処理を共通化できます。
例えば、特定のIDが見つからなかった場合に発生させる独自の例外クラスを定義し、その例外が発生した場合に404レスポンスを返すように設定できます。
例として、exceptions.py
のようなファイルを作成し、独自の例外を定義します。
# exceptions.py
class TodoNotFoundError(Exception):
"""指定されたTODOが見つからなかった場合に発生する例外"""
def __init__(self, todo_id: int):
self.todo_id = todo_id
そして、main.py
でこの例外に対するハンドラーを登録します。
# main.py
from fastapi import FastAPI, Depends, HTTPException, Request, status
from fastapi.responses import JSONResponse
from sqlalchemy.orm import Session
from . import crud, models, schemas
from .database import SessionLocal, engine
from .exceptions import TodoNotFoundError # 新しく作成した例外クラスをインポート
# ... (get_db関数などはそのまま)
app = FastAPI()
# TodoNotFoundErrorに対する例外ハンドラーを登録
@app.exception_handler(TodoNotFoundError)
async def todo_not_found_exception_handler(request: Request, exc: TodoNotFoundError):
return JSONResponse(
status_code=status.HTTP_404_NOT_FOUND,
content={"detail": f"Todo with id {exc.todo_id} not found"},
)
# ... (APIエンドポイントの定義)
# 指定したIDのTODO取得エンドポイントを修正
@app.get("/todos/{todo_id}", response_model=schemas.Todo)
def read_todo(todo_id: int, db: Session = Depends(get_db)):
db_todo = crud.get_todo(db, todo_id=todo_id)
if db_todo is None:
# HTTPExceptionではなく独自の例外を発生させる
raise TodoNotFoundError(todo_id=todo_id)
return db_todo
# ... (update_todo, delete_todo エンドポイントも同様に修正)
このようにすることで、エラー発生箇所では独自の例外をraiseするだけで済み、エラーレスポンスの形式変更などがハンドラー側で一括して行えるようになります。
バリデーション部分を共通化
今回の例ではPydanticモデルを使ってリクエストボディやレスポンスのバリデーションを行っています。これは既に共通化された良い状態と言えます。Pydanticモデルを変更するだけで、関連するAPIエンドポイントのバリデーションルールが一括で更新されます。
もし、複数のエンドポイントで共通のバリデーションロジックが必要になった場合は、独自の依存性関数を作成したり、Pydanticのカスタムバリデーターを活用したりすることで、コードの重複を防ぐことができます。
データベースとのやり取りをする層を分離
すでに crud.py
としてデータベース操作を分離していますが、これはデータアクセス層としてさらに洗練させることができます。例えば、特定のモデルに対するCRUD操作をまとめたクラス(Repositoryパターンなど)を作成することで、よりオブジェクト指向的にデータベースを扱えるようになります。
これにより、APIエンドポイントのコードはさらにシンプルになり、ビジネスロジックに集中できるようになります。また、データアクセス層を分離することで、ユニットテストを書く際にデータベースに依存しないテスト(モックを使ったテスト)が容易になります。
現状の crud.py
は関数ベースですが、規模が大きくなってきたらクラスベースに移行することを検討してみてください。
まとめ
この記事では、Pythonを使ったバックエンド開発でよく利用される FastAPI, Pydantic, SQLAlchemy, Alembic を組み合わせた構成で、CRUD操作を行うシンプルなREST APIを実装する手順をハンズオン形式で説明しました。
具体的には、以下の内容を学びました。
- FastAPI, Pydantic, SQLAlchemy の基本的な役割と組み合わせるメリット
- Poetryを使ったプロジェクトの依存関係管理と環境構築
- TODOアプリの簡単なテーブル設計とAPI要件定義
- SQLAlchemyを使ったORMモデルの定義
- Alembicを使ったデータベースマイグレーションの実行
- FastAPIのエンドポイント実装と、Pydanticを使ったリクエスト/レスポンスのスキーマ定義
- SQLAlchemyを使ったデータベースCRUD操作の実装 (
crud.py
として分離) - FastAPIの依存性注入 (
Depends
) を使ったデータベースセッションの管理 - Swagger UIやcurlを使ったAPIのテスト方法
- コードの保守性を高めるためのリファクタリングの考え方(エラー処理の共通化、データアクセス層の分離)
これで、Pythonを使ったモダンなバックエンド開発の基礎が身についたかと思います。
今回のTODOアプリは非常にシンプルな例でしたが、ここからさらに認証機能、ユーザー管理、より複雑なデータ構造やリレーションシップ、非同期処理の詳細、テストコードの実装など、学ぶべきことはたくさんあります。
ぜひ公式ドキュメントなども参考にしながら、さらに深く学びを進めていってください。この記事があなたのPythonバックエンド開発の第一歩になれば幸いです。
おまけ
Next.jsで自分のキャパシティを把握しながらTodo管理ができるアプリを開発・リリースしています!
「3日坊主になってしまう」、「Todoは作るけど結局予定がくるってタスクをこなせない。。」といった悩みを抱える方にうってつけのアプリになっていますので是非1度使ってみてください。
Discussion