【Webアプリ開発2026 #19】PythonでAPIを開発する

使用ライブラリ

  • FastAPI(Webフレームワーク)
  • Pydantic(データバリデーション)
  • SQLAlchemy(ORM)

FastAPI

FastAPIとは

Pythonの型ヒントに基づいてAPIを構築するためのモダンなWebフレームワーク。「フレームワーク」の回で紹介したマイクロフレームワークに分類される。

FastAPIの特徴

FastAPIの使い方

最もシンプルなFastAPI

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

この数行だけで以下が実現される。

  • http://localhost:8000/ にGETリクエストを送ると {"message": "Hello World"} が返る
  • http://localhost:8000/docs でSwagger UIが表示される
  • http://localhost:8000/redoc でReDocが表示される

パスパラメータ

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}
  • /items/42 にアクセスすると {"item_id": 42} が返る
  • item_id: int と型注釈をつけることで、文字列が来た場合は自動で422エラーを返す

クエリパラメータ

from fastapi import FastAPI

app = FastAPI()

fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]

@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
    return fake_items_db[skip : skip + limit]
  • /items/?skip=1&limit=2 でリストの1番目から2件取得できる
  • デフォルト値があるパラメータは省略可能

リクエストボディ(Pydanticモデル)

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float
    description: str | None = None

@app.post("/items/", status_code=201)
async def create_item(item: Item):
    return item
  • POSTリクエストのボディをPydanticモデルとして受け取る
  • JSONの自動パース、バリデーション、OpenAPIドキュメントへの反映が全て行われる
  • description はOptional(省略可能)

PUT / PATCH / DELETE

class ItemUpdate(BaseModel):
    name: str
    price: float
    description: str | None = None

class ItemPatch(BaseModel):
    name: str | None = None
    price: float | None = None
    description: str | None = None

@app.put("/items/{item_id}")
async def update_item(item_id: int, item: ItemUpdate):
    return {"item_id": item_id, **item.model_dump()}

@app.patch("/items/{item_id}")
async def patch_item(item_id: int, item: ItemPatch):
    return {"item_id": item_id, **item.model_dump(exclude_unset=True)}

@app.delete("/items/{item_id}", status_code=204)
async def delete_item(item_id: int):
    return None
  • PUT: 全フィールドを送る(ItemUpdateの全フィールドが必須)
  • PATCH: 変更したいフィールドだけ送る(ItemPatchの全フィールドがOptional)
  • DELETE: レスポンスボディなし(204 No Content)

SQLAlchemy

FastAPIとよく一緒に使用されるORM(Object-Relational Mapping)の一つ。Pythonのクラスとデータベースのテーブルを対応付け、SQLを直接書かずにデータベース操作ができる。

テーブル定義

from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "user"

    id: Mapped[int] = mapped_column(primary_key=True)
    email: Mapped[str] = mapped_column(unique=True, nullable=False)
    password: Mapped[str] = mapped_column(nullable=False)
    name: Mapped[str] = mapped_column(nullable=False)
  • Pythonのクラスがそのままデータベースのテーブル定義になる
  • 型注釈(Mapped[int]等)でカラムの型を表現する

データ取得

from sqlalchemy import select
from sqlalchemy.orm import Session
from .models import User

def get_user(db: Session, user_id: int):
    return db.scalars(select(User).where(User.id == user_id)).first()
  • select(User).where(User.id == user_id) でSQLの SELECT * FROM user WHERE id = ? に相当する処理を記述できる
  • SQLを直接書かずにPythonのコードとして表現できるため、型チェックやIDEの補完が効く

async/await対応版

from sqlalchemy.ext.asyncio import AsyncSession

async def get_user(db: AsyncSession, user_id: int):
    result = await db.scalars(select(User).where(User.id == user_id))
    return result.first()
  • AsyncSessionを使い、awaitをつける以外は同一

Pydantic BaseModel

APIの入出力データの構造を定義するためのクラス。FastAPIはPydanticモデルを使ってリクエスト/レスポンスのバリデーションとシリアライズを行う。

from pydantic import BaseModel, EmailStr

class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None
  • 型に合わないデータが来たらバリデーションエラー(422)を自動で返す
  • EmailStr のように特殊な型を使うと、メールアドレスの形式チェックも自動で行われる
  • APIドキュメントにそのままスキーマとして反映される

uvicorn

FastAPIアプリケーションを実行するためのASGIサーバー。開発時も本番時もuvicornを使ってアプリケーションを起動する。

uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
  • app.main:app は「app/main.pyファイルのapp変数」を指す
  • --reload をつけるとコード変更時に自動でサーバーが再起動する(開発時のみ使う)
  • 本番ではgunicorn + uvicorn workerや --workers オプションで複数プロセスを起動するのが一般的