Claude Media
Claude CodeでFastAPIバックエンドを構築する — 型ヒントを軸にした実装フロー

Claude CodeでFastAPIバックエンドを構築する — 型ヒントを軸にした実装フロー

Claude CodeでFastAPIバックエンドを作る際の環境構築、CLAUDE.mdや公式Skillでの型ヒント規約の固定、PostToolUseフックでの型チェック自動化までをまとめます。

Claude CodeでFastAPIバックエンドを作るとは

Claude CodeでFastAPIバックエンドを作るとは、型ヒントを軸にしたFastAPIの設計をClaude Codeに理解させ、CLAUDE.mdや.claude/rules/で規約を固定しながら実装させる進め方です。FastAPIはPythonの型ヒントからリクエストの検証・ドキュメント生成・エディタ補完を自動で組み立てるフレームワークで、この型ヒントはそのままClaude Codeが読む仕様にもなります。

FastAPIの公式ドキュメントは、コードブロックをそのままコピーして動く実例として案内しており、エディタで書いて初めて「書く量の少なさ・自動の型チェック・補完」の恩恵が分かるとしています。この型情報はエディタだけでなくClaude Codeにも同じ形で見えるため、型ヒントが揃っているほどClaude Codeが生成するコードも仕様からずれにくくなります。

FastAPIには、AIコーディングエージェント向けの公式Skillも用意されています。uvx library-skillsでインストールでき、Claude Codeを含む複数のエージェントに対応します。この記事では、環境構築から公式Skillの導入、規約の固定、実行と検証、型チェックの自動化までを順に扱います。

環境をセットアップする

最初にFastAPIのプロジェクトを作り、公式Skillを導入します。FastAPIの公式ドキュメントはuvでのセットアップを案内しています。

uv init awesome-project --bare
cd awesome-project
uv add "fastapi[standard]"

uv init --bareは最小限のpyproject.tomlだけを作り、サンプルのmain.pyやREADMEは生成しません。アプリ本体のファイルはこの後にClaude Codeへ書かせます。uv addは.venvを作ってpyproject.tomlに依存を追加し、同じバージョンを再現できるようuv.lockも作ります。

uv add "fastapi[standard]"は、FastAPI Cloudへのデプロイに使うfastapi-cloud-cliを含む標準の依存関係一式を入れます。これらの追加依存が不要ならuv add fastapiだけで済み、fastapi-cloud-cliだけを外したいならuv add "fastapi[standard-no-fastapi-cloud-cli]"を使います。

続けて公式Skillを導入します。FastAPIに同梱されたlibrary-skillsコマンドが、インストール済みのFastAPIのバージョンに合わせたガイダンスを生成します。

uvx library-skills

インストール先を聞かれたら.claude/skillsを選びます。Codex・Cursor・GitHub Copilot・Gemini CLIなど他のエージェントにも対応していますが、この記事ではClaude Codeでの利用を前提にします。プロジェクトのFastAPIを更新すると、このSkillの内容もそのバージョンに追随します。

uvを使わず既存の仮想環境に入れるなら、pip install "fastapi[standard]"でも導入できます。この場合はuv.lockが作られないので、バージョンの固定はrequirements.txtなどで自分で管理します。

開発サーバーの起動はfastapi devです。

uv run fastapi dev

起動するとhttp://127.0.0.1:8000/docsに自動生成されたAPIドキュメントが立ち上がります。ここまでが済んだ状態から、Claude Codeにエンドポイントの実装を任せていきます。VS CodeのDevContainerやCodespaces上で環境を作る場合の手順はClaude Code CodespacesでDevContainer開発を始める手順にまとめています。

CLAUDE.mdと.claude/rules/で型ヒントの規約を固定する

型ヒントはFastAPIが自動で検証・ドキュメント化する仕組みの土台ですが、書き方が揃っていなければ恩恵は半減します。CLAUDE.mdは会話の開始時に毎回読み込まれるファイルで、プロジェクト全体に常に効かせたい規約を置く場所です。

# API実装の規約
- リクエスト・レスポンスは必ずPydanticモデルの型ヒントで表現する
- パスパラメータには具体的な型(str, int, UUID等)を付ける
- 生のdictやAnyを返り値の型に使わない

規約が増えてきたら.claude/rules/ディレクトリに分割し、対象ファイルを絞って読み込ませます。pathsフロントマターにglobパターンを指定すると、ClaudeがRead・Write・Editのいずれかのツールで該当パスのファイルを扱ったときにそのルールが読み込まれます。pathsのないルールは起動時に無条件で読み込まれます。

---
paths:
  - "app/api/**/*.py"
  - "app/schemas/**/*.py"
---
 
# APIエンドポイントの規約
- エンドポイント関数の引数と返り値に型ヒントを必ず付ける
- ステータスコードは`response_model`と`status_code`で明示する
- 例外は`HTTPException`で送出し、素の`Exception`を投げない

pathsのglob展開には上限があります。ルール1件あたり展開後のパターン数1,000個・4MiBまでの予算が共有され、{}によるブレース展開はグループごとに掛け算で増えるため、拡張子の書き分けが多いルールほど予算を圧迫します。予算を超えるパターンは展開されないまま扱われ、波かっこがそのまま文字として残るためどのファイルにもマッチしません。v2.1.217より前は、波かっこのグループが多いpathsで起動時にCLIが固まったりクラッシュしたりしました。

全プロジェクト共通の規約は~/.claude/rules/に置くと、すべてのプロジェクトに適用されます。特定のプロジェクト間だけで共有するためのシンボリックリンクは外部importとして承認が要り、paths付きのルールは読み込まれません。バックエンドの設計を仕様から固めてから実装に入りたい場合は、仕様駆動開発(cc-sdd)の実践の進め方と組み合わせても機能します。

/runと/verifyでエンドポイントの動作を確認する

Claude Codeには、アプリを実際に起動して変更を確認するためのバンドル済みSkillが3つあります。

起動と確認

バンドル済みの3つのSkill

  • /run

    アプリを起動し、動いている状態を見せます。

  • /verify

    アプリをビルド・起動し、テストや型チェックに頼らず変更が意図どおり動くかを確かめます。

  • /run-skill-generator

    /runと/verifyにプロジェクト固有の起動方法を教えます。

/runと/verifyは設定なしで動きます。プロジェクトの種類(CLI・サーバー・ブラウザー主体)や、READMEとpackage.json、Makefileの中身から起動方法を推測するためです。FastAPIのようにfastapi devだけで起動する構成なら、この推測はほぼ外れません。

一方で、DBマイグレーションやenvファイル、複数ステップのビルドが要る構成では推測が外れやすくなります。そこで使うのが/run-skill-generatorです。クリーンな環境から実際にアプリを起動させ、必要だったインストールコマンドや環境変数、起動スクリプトを.claude/skills/run-<name>/にプロジェクト固有のSkillとして記録します。一度記録すれば、/runや/verifyだけでなくリポジトリ内の他のエージェントも同じ手順に従います。ビルドや起動の手順が変わったときは、このコマンドを再度実行します。

/verify自身も、レシピなしでビルドと操作をやり切ったときに、動いた手順をリポジトリルートの.claude/skills/verify/SKILL.mdへ書き足します(Claude Code v2.1.200以降)。以降はバンドル版の代わりにこの記録済みSkillが使われ、モノレポでは触ったパッケージのディレクトリに書かれます。

PostToolUseフックで型チェックを自動化する

/verifyはまとまった単位で動作を確認する手段ですが、編集のたびに型の矛盾を検出したい場合はPostToolUseフックを使います。テストの合否を締め条件にする進め方はClaude CodeでのTDDの回し方で扱っていますが、ここでは型チェックに絞った例を示します。

.claude/settings.jsonに、EditまたはWriteツールの実行後に発火するフックを登録します。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/type-check.sh"
          }
        ]
      }
    ]
  }
}

スクリプト側で、編集されたファイルが.pyかどうかを見てからmypyを走らせます。ここで効くのは、mypyの出力を標準エラーに回す1行です。

#!/usr/bin/env bash
input=$(cat)
file=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty')
 
if [[ "$file" == *.py ]]; then
  if ! out=$(uv run mypy "$file" --ignore-missing-imports 2>&1); then
    printf '%s\n' "$out" >&2
    exit 2
  fi
fi

PostToolUseで終了コード2を返すと、Claudeに見えるのは標準エラー出力です。終了コード0の標準エラーはデバッグログにだけ残り、Claudeには届きません。

mypyの指摘をechoの定型文に置き換えて標準出力へ流すと、エラーの中身がClaudeに渡らず「型エラーが残っています」とだけ伝わります。2つの書き方の出力は次のとおりです。

くらべる

同じ型エラーを、どちらの書き方で返すか

Claudeに届かない

mypyの出力が標準出力に残る版

終了コードは2ですが、標準エラーに出るのは「型エラーが残っています。修正してから次に進んでください。」の1行だけです。app/main.py:7: error: Incompatible return type ...の本文は標準出力に出て、Claudeに渡る側にはありません。

Claudeに届く

2>&1で束ねて標準エラーへ出す版

終了コードは2で、標準エラーにapp/main.py:7: error: Incompatible return type (got "dict[str, Any]", expected "Item") [return-value]がそのまま出ます。標準出力は空です。入力のfile_pathがREADME.mdなら何も出ず、終了コードは0でした。

フックの置き場所はスコープを決めます。.claude/settings.jsonはプロジェクト単位でリポジトリにコミットでき、チーム全員に同じフックを配ります。個人だけの設定は.claude/settings.local.jsonに置きます。Claude Codeが設定をこのファイルへ保存するときに、gitignore対象にします。mypyをこのフックで走らせる前提として、uv add --dev mypyのように開発用依存として追加しておく必要があります。

Claude Codeでの実装フロー使い分け早見表

ここまでの要素は役割が異なります。どれか1つで済ませるのではなく、場面に応じて組み合わせます。

用途使うもの向く場面
型ヒントの規約を常に効かせる使うものCLAUDE.md / .claude/rules/向く場面エンドポイント全体で守らせたい規約
FastAPI固有の実装知識を都度参照する使うものFastAPI公式Skill向く場面Pydanticモデルやルーティングの書き方に迷うとき
起動して動作を目で確認する使うもの/run /verify向く場面変更がAPIとして動くかどうかの確認
起動手順をプロジェクトに固定する使うもの/run-skill-generator向く場面DBやenvが要って推測が外れる構成
編集のたびに型エラーを検出する使うものPostToolUseフック向く場面型ヒントの矛盾を即座に拾いたいとき

よくあるつまずき

/runと/verifyの推測が外れる

DBへの接続やenvファイルの読み込みが要る構成だと、README頼みの推測は失敗しやすくなります。毎回同じ理由で外れるなら、/run-skill-generatorで起動手順を一度記録し、以降は推測させない形に変えます。

.claude/rules/のpathsが効かない

pathsのglobパターンに[が含まれ、かつブラケット表現として解釈できない形になっていると、そのパターンは何にもマッチしなくなります。ファイル名に角かっこを使う場合は\[のようにエスケープします。ルール全体の展開予算(1,000パターン・4MiB)を超えたパターンも同様にマッチしません。

pathsの書き方を間違えるとルールが常時読み込まれる

frontmatterのYAMLが壊れて解釈できないと、Claude Codeはfrontmatterを無視し、そのルールをpathsなしとして読み込みます。対象ファイルを絞ったつもりのルールが起動時から毎回読み込まれていたら、YAMLの書式を疑います。

Bash経由で生成したファイルにフックが効かない

alembic revision --autogenerateのようにBashコマンドがマイグレーションファイルを生成した場合を考えます。この場合EditやWriteツールを経由していないため、matcher: "Edit|Write"のPostToolUseフックは発火しません。Bashコマンドの結果を検証したいときは、matcherをBashにした別のフックを用意します。

disableBundledSkillsで/runと/verifyが消える

この設定を有効にしていると、/runや/verifyを含むバンドル済みSkillそのものが使えなくなります。チームの設定を引き継いだプロジェクトで両コマンドが見当たらないときは、まずこの設定を確認します。

.claude/rules/と.claude/skills/の役割を混同する

どちらも.claude/配下に置きますが、読み込まれる条件が違います。

くらべる

規約の置き場所の分け方

条件に合えば読み込まれる

.claude/rules/

pathsなしなら起動時に常に、pathsありなら対象ファイルをRead・Write・Editしたときに読み込まれます。型ヒントの規約のように、守らせ続けたい内容向きです。

必要なときだけ読み込まれる

.claude/skills/

呼び出したとき、またはClaudeが関連すると判断したときだけ読み込まれます。FastAPI固有の実装知識のように、参照したい場面が限られる内容向きです。

常駐させる量はルール側が決めるので、Skillに寄せられる内容は寄せると文脈を節約できます。

まとめ

型ヒントの規約は常時読み込まれるルールに、FastAPI固有の知識は必要なときだけ呼ぶSkillに置き分けるのが出発点です。型チェックのフックは、mypyの出力を標準エラーへ流す形にして初めてClaudeの修正材料になります。

DBやenvファイルが絡んで/runの推測が外れる構成では、/run-skill-generatorで起動手順を先に記録しておくと以降の往復が減ります。完成したバックエンドをコンテナ化して開発・本番のクラスタに載せる段階に進むなら、Docker/Podman/Kubernetes MCPの選び方が次の分岐点の整理に役立ちます。

この記事を共有:XはてブLinkedIn