FastAPIとは|最短で動かす手順とasync/defの使い分け【2026年版】
FastAPIは、Pythonの型ヒントをそのままAPIの仕様として使うWebフレームワークです。関数の引数に item_id: int と書けば、型変換・入力検証・エラーレスポンス・OpenAPIドキュメントが同時に手に入ります。ただし公式が推奨する起動方法は2024年以降 uvicorn main:app --reload から fastapi dev に変わっており、日本語の入門記事の多くは古い手順のままです。ここでは2026年7月時点の最新版0.139.0を前提に、最短でAPIを動かす手順、実務で最も事故が多い async def と def の使い分け、そしてFastAPIを選ぶべきでない場面までを整理します。
目次
まとめ:FastAPIの要点
- 正体:Webの土台がStarlette、データ検証がPydantic。FastAPIはこの2つを型ヒントで束ねる薄い層で、独自ORMや管理画面は持たない。
- 要件:最新版は0.139.0(2026年7月時点)。Python 3.10以上が必須で、3.9以下は動かない。
- 導入:
pip install "fastapi[standard]"→fastapi devで開発サーバー、fastapi runで本番。公式チュートリアルはこの2コマンドに統一済み。 - 非同期:
awaitできないライブラリ(多くの同期DBドライバ)を使う関数はasync defにしない。公式の指針は「迷ったらdef」。 - 選び分け:管理画面・認証・ORMが最初から要るならDjango。APIサーバー単体、特に型付きJSONを大量に返す用途がFastAPIの主戦場。
- 注意:
fastapi[standard]には商用サービスへのデプロイCLI(fastapi-cloud-cli)が同梱される。不要ならfastapi[standard-no-fastapi-cloud-cli]を使う。
FastAPIとは:型ヒントを仕様として扱うAPIフレームワーク
FastAPIは、Sebastián Ramírez氏が開発するPython製のWebフレームワークです。公式ドキュメントが明言しているとおり、FastAPIはStarlette(Web部分)とPydantic(データ部分)の上に立つ構造で、HTTPの処理はStarletteに、値の検証と変換はPydanticに任せています。FastAPI自身が担うのは、関数の型ヒントを読み取って両者を接続し、OpenAPIスキーマを生成する部分です。
「速い」と言われる理由もこの構造にあります。WSGIではなくASGI上で動くStarlette(Linux・macOSではuvloop込みのUvicorn。Windowsは標準のasyncioにフォールバックする)が土台であり、公式が性能の根拠として挙げているのは第三者ベンチマークのTechEmpowerです。FastAPI自体が独自の高速化を実装しているわけではありません。
この設計のため、DjangoのようにORM・管理画面・認証・テンプレートまで揃った「全部入り」ではありません。APIを返すことに特化した部品であり、足りないものは自分で選んで足す前提のフレームワークです。
FastAPIで何ができるのか
1つの関数定義から、次の4つが同時に生成されます。これがFastAPIの実質的な価値です。
| 得られるもの | 根拠となる記述 |
|---|---|
| リクエストの型変換 | 引数の型ヒント(item_id: int) |
| 入力バリデーションと422応答 | Pydanticモデル・型ヒント |
OpenAPIスキーマ(/openapi.json) |
関数シグネチャ全体 |
対話型ドキュメント(/docs・/redoc) |
OpenAPIスキーマから自動生成 |
REST APIやマイクロサービスのバックエンド、機械学習モデルの推論エンドポイント、SPAのAPIサーバーが典型的な用途です。逆にサーバーサイドでHTMLを描画する用途は、Jinja2テンプレートを使えば可能ではあるものの、FastAPIの利点がほとんど効きません。
最新版と動作要件(2026年7月時点)
| 項目 | 値 |
|---|---|
| FastAPI最新版 | 0.139.0 |
| 必要なPython | 3.10以上 |
| Starlette | 0.46.0以上(最新1.3.1) |
| Pydantic | 2.9.0以上(最新2.13.4) |
| ライセンス | MIT |
Python 3.10未満のサポートは打ち切られています。str | None のようなUnion記法を型ヒントに使えるのもこの要件のためです。Pydanticはv2系が前提で、v1系の @validator や parse_obj() をそのまま書いた入門記事のコードは現行版では動きません。バージョンは更新が速いため、導入前にPyPIの最新版を確認し、インストール後は fastapi --version で実際に入った版を照合してください。
最短の起動手順:fastapi[standard] と fastapi dev
インストールから起動まで2コマンド
仮想環境を有効にしたうえで、標準の依存関係込みでインストールします。
pip install "fastapi[standard]"
クォートは必須です。zshなどでは角括弧がグロブとして解釈され、囲まないとインストールに失敗します。
次に main.py を作ります。
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None):
return {"item_id": item_id, "q": q}
起動します。
fastapi dev
ファイル名の指定すら不要です。fastapi dev は main.py を自動的に読み取り、その中のFastAPIアプリを検出して、自動リロードを有効にしたUvicornを立ち上げます。http://127.0.0.1:8000/items/5?q=somequery を開けば {"item_id": 5, "q": "somequery"} が返り、/docs にはSwagger UIが、/redoc にはReDocが既に生成されています。
従来広く紹介されてきた uvicorn main:app --reload も現在も動作しますが、公式チュートリアルの標準手順は fastapi dev(開発)と fastapi run(本番)に置き換わりました。この2つのコマンドはfastapi-cli経由で提供され、standard 依存に含まれています。
パスパラメータとクエリパラメータの振り分け規則
上のコードで、item_id はURLパスの {item_id} に対応するためパスパラメータ、q はパスに現れないためクエリパラメータとして扱われます。宣言の場所を書き分ける必要はなく、パスに同名の波括弧があるかどうかだけで自動的に振り分けられます。
型ヒントは変換規則でもあります。item_id: int と書けば /items/5 の "5" は整数5になり、/items/abc にアクセスすれば、どの引数が不正かを示すJSONとともにHTTP 422が返ります。エラーハンドリングを自分で書く必要はありません。
Pydanticモデルによるリクエストボディ検証と422応答
POSTで受け取るJSONは、Pydanticモデルを引数の型に指定するだけで検証されます。
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str
price: float = Field(gt=0)
tax: float | None = None
@app.post("/items/")
def create_item(item: Item):
total = item.price + (item.tax or 0)
return {"name": item.name, "total": total}
price に0以下や文字列が来ればリクエストは422で弾かれ、ハンドラの中には到達しません。同時に、このモデルはOpenAPIスキーマのリクエストボディ定義として /docs に反映されます。型定義・検証・ドキュメントが1箇所に集約されることが、FastAPIが「短く書ける」と言われる中身です。
ここから先も追加ライブラリは要りません。ファイルを分割するなら APIRouter でルーターを切って app.include_router() でぶら下げ、ブラウザのSPAから叩くなら CORSMiddleware をミドルウェアとして登録し、トークン認証は OAuth2PasswordBearer を依存として受け取るのが標準経路です。いずれも fastapi から import でき、追加インストールは不要です(CORSMiddleware はStarlette由来の再輸出)。
async def と def の使い分け:迷ったら def
FastAPIで最も事故が多いのがここです。「FastAPIは非同期だから async def で書くべき」という理解は誤りで、間違った場所に async def を書くとむしろ性能が落ちます。公式の判断基準は明快です。
| 使うライブラリ | 関数の宣言 | 実行のされ方 |
|---|---|---|
await で呼ぶ(非同期対応) |
async def |
イベントループ上で実行 |
await できない(同期DBドライバ等) |
def |
外部スレッドプールで実行 |
| 何とも通信しない計算のみ | async def |
イベントループ上で実行 |
| 判断がつかない | def |
外部スレッドプールで実行 |
ただし3行目には注釈が要ります。ここで言う「計算のみ」は軽い処理を指し、重いCPUバウンド処理を async def に置けば同じくイベントループが止まります。長い計算は def でスレッドプールへ逃がすか、Celeryなどの外部ワーカーに寄せてください。
要点は、FastAPIが def のパス関数を外部スレッドプールに逃がして実行することです。だから同期的なDB接続やファイルI/Oを含む関数を素の def で書いても、サーバー全体はブロックされません。ただしスレッド数には上限があり(AnyIOの既定は40)、数秒かかる同期処理を大量に def で流せばプールが枯渇して後続が待たされます。上限は anyio.to_thread.current_default_thread_limiter().total_tokens で引き上げられますが、まずは同期処理そのものを短くする設計を優先してください。
危険なのは逆のパターンです。async def の中で await しない同期処理(psycopg2での問い合わせ、httpx.get() の同期API、time.sleep())を呼ぶと、その処理が終わるまでイベントループが停止し、他の全リクエストが待たされます。同時接続を捌くつもりで async def を付けた結果、直列実行より遅くなるのはこの経路です。
import time
import httpx
from fastapi import FastAPI
app = FastAPI()
# 悪い例:async def の中で同期I/Oを呼びイベントループを止める
@app.get("/bad")
async def bad():
r = httpx.get("https://example.com") # 同期API。await できない
time.sleep(1)
return {"status": r.status_code}
# 良い例:同期ライブラリを使うなら def にする(スレッドプールで実行される)
@app.get("/good")
def good():
r = httpx.get("https://example.com")
time.sleep(1)
return {"status": r.status_code}
# 非同期対応ライブラリを await で呼ぶなら async def が正しい
@app.get("/best")
async def best():
async with httpx.AsyncClient() as client:
r = await client.get("https://example.com")
return {"status": r.status_code}
この規則はパス関数だけでなく依存関係(Depends)にも同じく適用されます。def で書いた依存はスレッドプールで、async def で書いた依存はイベントループ上で実行されます。認証チェックのために依存の中で同期的にDBを引いているなら、その依存は def のままにしておくのが正解です。
FlaskやDjangoとの違いと、FastAPIを選ぶべきでない場面
「Flaskから移行すべきか」は検索でも頻出しますが、判断軸は作るものがAPIだけかどうかに尽きます。
| 観点 | FastAPI | Flask | Django |
|---|---|---|---|
| 主な用途 | API(JSON) | 小規模Web全般 | フルスタックWeb |
| 入力検証 | 標準(Pydantic) | 拡張で追加 | Forms・DRF |
| APIドキュメント | 自動生成 | 拡張で追加 | DRFで追加 |
| ORM | 非同梱 | 非同梱 | 同梱 |
| 管理画面 | なし | なし | 同梱 |
| 非同期 | ASGIで標準 | 限定的 | 対応(部分的) |
FastAPIを選ぶべきでないのは次の場合です。まず、管理画面・ユーザー認証・ORM・マイグレーションが最初から必要な業務システム。これらをFastAPIで揃えるとSQLAlchemy、Alembic、認証ライブラリを個別に選定・接続することになり、Djangoが標準で持つものを再実装する形になります。次に、サーバーサイドでHTMLを描画する従来型のWebサイト。型ヒントによる自動検証もOpenAPI生成もJSONを返さない画面では働かず、利点が消えます。
逆に、既存のFlask製APIに手作業のバリデーションとSwagger定義が積み上がっているなら、FastAPIへの移行は割に合います。両者ともデコレータでルーティングを書く構造は似ており、@app.route("/x", methods=["POST"]) を @app.post("/x") に、手書きの入力チェックをPydanticモデルに置き換える作業が中心になるためです。
本番投入で踏みやすい落とし穴
fastapi[standard] に同梱されるfastapi-cloud-cli
pip install "fastapi[standard]" でインストールされる依存には、Uvicornやhttpxに加えて fastapi-cloud-cli(FastAPI Cloudへデプロイするためのツール)が入ります。正確には fastapi-cli[standard] 経由の推移的依存で、fastapi コマンド一式に付いてくる形です。本番用のコンテナイメージに外部サービスのCLIを入れたくない場合、公式は専用の指定を用意しています。
pip install "fastapi[standard-no-fastapi-cloud-cli]"
依存を最小にするなら pip install fastapi のみでも動きますが、この場合はUvicornも fastapi コマンドも入らないため、サーバーを別途インストールする必要があります。
本番で公開されたままの /docs と /openapi.json
Swagger UIとOpenAPIスキーマは既定で公開されます。社内APIや認証前提のエンドポイントでも、/docs と /openapi.json にアクセスすれば全エンドポイントの仕様が読める状態です。本番では FastAPI(docs_url=None, redoc_url=None, openapi_url=None) で無効化するか、認証の背後に置く判断が要ります。表示のカスタマイズや無効化の具体的な手順はFastAPIのSwagger UI(/docs)自動生成|表示・カスタマイズ・本番で無効化する手順で解説しています。
fastapi run のワーカー数とコンテナ配置
本番では自動リロードを外した fastapi run を使います。複数コアを使い切るにはワーカーを指定します。
fastapi run --workers 4 main.py
ただしKubernetes上で動かす場合、公式ドキュメントはワーカーを使わずコンテナごとに単一プロセスを走らせることを推奨しています。レプリケーションはコンテナ側の仕組みに任せ、プロセス内で二重に多重化しないという考え方です。コンテナ化の具体的な構成はDockerを用いたFastAPIとReactのコンテナ化とデプロイ方法が参考になります。
DB・フロントエンド接続の自前構成
FastAPIはORMを持たないため、データベース連携はSQLAlchemyなどを組み合わせます。モデル定義とセッション管理の設計はFastAPIとSQLAlchemyでのモデルの構築方法とベストプラクティスにまとめています。同期のSQLAlchemyを使うなら、前述のとおりパス関数は def で書くのが安全です。SPAと組み合わせる構成はFastAPIとReactとDockerを使用したフルスタックアプリケーションの構築方法を参照してください。
よくある質問
FastAPIは何ができますか?
型ヒントの付いたPython関数からREST APIを構築し、リクエストの型変換・入力バリデーション・OpenAPIスキーマ・対話型ドキュメント(/docs)を自動生成します。ORMや管理画面は含まないため、API層に絞ったフレームワークです。
FastAPIとREST APIの違いは何ですか?
REST APIはHTTPを使ったAPIの設計様式(スタイル)の名前で、FastAPIはそのREST APIをPythonで実装するためのフレームワークです。比較の対象ではなく、FastAPIでREST APIを作る、という関係になります。
起動は fastapi dev と uvicorn のどちらを使うべきですか?
開発時は fastapi dev が公式の標準です。main.py とアプリを自動検出し、内部でUvicornを自動リロード付きで起動します。uvicorn main:app --reload も引き続き動作しますが、明示的な指定が必要になるだけで得るものはほとんどありません。ASGIサーバーのオプションを細かく制御したい場合や、プロセス管理を別のツールに任せる構成でのみ、直接起動を選ぶ理由があります。
Flaskから移行する価値はありますか?
APIサーバーとして使っていて、入力チェックやSwagger定義を手書きしているなら価値があります。その部分がPydanticとOpenAPI自動生成に置き換わるためです。逆に、HTMLテンプレートを返す画面が中心のFlaskアプリは、移行しても得られる利点がほとんどありません。
非同期処理は必ず async def で書く必要がありますか?
必要ありません。await できないライブラリ(多くの同期DBドライバなど)を使う関数は def で宣言してください。def のパス関数はFastAPIが外部スレッドプールで実行するため、サーバー全体を止めません。async def の中で同期処理を呼ぶ方が危険です。より詳しくは、Uvicornの記事で整理しています。