0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FlaskとFastAPIの使い分け — どっちを選ぶか整理した

0
Posted at

はじめに

前の記事でFlaskの基本を触った。

「結局どっちを使えばいいの?」という疑問が残ったので、もう少し深掘りして整理した。同期/非同期・用途・エコシステムの違いを軸に、実際に両方触ってみた上での個人的な判断基準をまとめる。


前提 — 2つのフレームワークの立ち位置

まず歴史的な背景を整理する。

Flask(2010年〜)
Armin Ronacher が作った「マイクロフレームワーク」。必要最小限の機能だけを提供して、あとは自分で選んで組み合わせる設計思想。14年の歴史があり、エコシステムが成熟している。

FastAPI(2018年〜)
Sebastián Ramírez が作ったAPI特化フレームワーク。Python 3.6以降の型ヒントを最大限活用する設計。Starletteというフレームワークの上に構築されていて、非同期処理がネイティブで動く。

PHPで言うとFlaskがSlim Framework、FastAPIがLaravel(API部分に絞ったもの)に近いイメージ。


同期と非同期の違い

一番根本的な違いがここ。

Flaskの同期モデル

# Flask — デフォルトは同期
import requests
from flask import Flask

app = Flask(__name__)

@app.route("/dashboard")
def dashboard():
    # これはブロッキング処理
    user  = requests.get("https://api.example.com/user/1").json()
    order = requests.get("https://api.example.com/orders").json()
    return {"user": user, "order": order}
    # user取得が終わるまでorder取得は始まらない → 合計待ち時間 = 直列

Flask 2.0以降でasync defも書けるようになったが、内部でスレッドを使う実装になっていて、asyncioのネイティブ非同期とは異なる。

# Flask 2.0以降 — async defは書けるが本物の非同期ではない
@app.route("/dashboard")
async def dashboard():
    # asyncioを使いたいなら別途設定が必要
    ...

FastAPIの非同期モデル

# FastAPI — ネイティブ非同期
import httpx
from fastapi import FastAPI

app = FastAPI()

@app.get("/dashboard")
async def dashboard():
    async with httpx.AsyncClient() as client:
        user_task  = client.get("https://api.example.com/user/1")
        order_task = client.get("https://api.example.com/orders")

        # 2つのリクエストを同時に実行
        user_res, order_res = await asyncio.gather(user_task, order_task)

    return {"user": user_res.json(), "order": order_res.json()}
    # 合計待ち時間 = max(user取得, order取得) → 並列で速い

APIが複数の外部サービスを叩くような構成では、FastAPIの非同期が効果を発揮する。


バリデーションの違い

前の記事でも触れたが、使い分けに直結するので改めて整理。

Flaskのバリデーション

標準では何もない。自前で書くかライブラリを選ぶ。

# 自前でバリデーション
from flask import request, jsonify

@app.route("/users", methods=["POST"])
def create_user():
    data = request.get_json()

    # 手動バリデーション(これが地味に面倒)
    if not data.get("name"):
        return jsonify({"error": "nameは必須です"}), 422
    if len(data["name"]) > 50:
        return jsonify({"error": "nameは50文字以内です"}), 422
    if not data.get("email"):
        return jsonify({"error": "emailは必須です"}), 422

    return jsonify({"name": data["name"]}), 201
# marshmallowを使う場合
from marshmallow import Schema, fields, validate, ValidationError

class UserSchema(Schema):
    name  = fields.Str(required=True, validate=validate.Length(max=50))
    email = fields.Email(required=True)

schema = UserSchema()

@app.route("/users", methods=["POST"])
def create_user():
    try:
        data = schema.load(request.get_json())
    except ValidationError as e:
        return jsonify({"errors": e.messages}), 422

    return jsonify({"name": data["name"]}), 201

FastAPIのバリデーション

Pydanticが標準で入っている。

from fastapi  import FastAPI
from pydantic import BaseModel, Field, EmailStr

app = FastAPI()

class UserCreate(BaseModel):
    name:  str       = Field(..., max_length=50)
    email: EmailStr

@app.post("/users", status_code=201)
def create_user(user: UserCreate):
    return {"name": user.name}
    # バリデーションエラーは自動で422レスポンスになる

コード量と可読性の差がある。バリデーションが多いAPIを作るほどFastAPIの優位性が出る。


ドキュメント生成の違い

Flask

デフォルトではSwagger UIが自動生成されない。flasggerflask-openapi3を入れて設定する必要がある。

pip install flasgger
from flasgger import Swagger

app = Flask(__name__)
swagger = Swagger(app)

@app.route("/users/<int:user_id>")
def get_user(user_id):
    """
    ユーザーを取得する
    ---
    parameters:
      - name: user_id
        in: path
        type: integer
    responses:
      200:
        description: ユーザー情報
    """
    return {"user_id": user_id}

docstringにYAMLを書くスタイルは正直つらい。

FastAPI

型ヒントを書くだけで/docsにSwagger UIが自動生成される。追加設定は不要。

@app.get("/users/{user_id}", summary="ユーザー取得", tags=["users"])
def get_user(user_id: int) -> UserResponse:
    return {"user_id": user_id}

APIドキュメントの自動生成は、FastAPIを選ぶ理由として一番わかりやすいメリットだと感じている。


テンプレートエンジン(HTML出力)

Webアプリとして画面を返したい場合はFlaskのほうが向いている。

Flask + Jinja2

from flask import render_template

@app.route("/users")
def user_list():
    users = [{"name": "田中"}, {"name": "鈴木"}]
    return render_template("users.html", users=users)
<!-- templates/users.html -->
<!DOCTYPE html>
<html>
<body>
  <ul>
    {% for user in users %}
      <li>{{ user.name }}</li>
    {% endfor %}
  </ul>
</body>
</html>

Jinja2はPHPのBladeに近い感覚で書ける。PHPエンジニアにはなじみやすい。

FastAPI

Jinja2Templatesを使えばHTMLも返せるが、設計としてはAPI(JSON)に特化している。フロントエンドをNext.jsなど別のフレームワークで作ってAPIとして使う構成のほうが自然。

from fastapi           import FastAPI, Request
from fastapi.templating import Jinja2Templates

app       = FastAPI()
templates = Jinja2Templates(directory="templates")

@app.get("/users")
def user_list(request: Request):
    users = [{"name": "田中"}, {"name": "鈴木"}]
    return templates.TemplateResponse(
        "users.html",
        {"request": request, "users": users},
    )

できなくはないが、FastAPIでHTMLを返すのは少し不自然に感じる。


エコシステムの成熟度

Flaskのほうが歴史が長い分、拡張ライブラリが多い。

機能 Flask拡張 FastAPI相当
ORM Flask-SQLAlchemy SQLAlchemy(直接)
認証 Flask-Login / Flask-JWT python-jose / authlib
マイグレーション Flask-Migrate(Alembic) Alembic(直接)
メール送信 Flask-Mail fastapi-mail
キャッシュ Flask-Caching aiocache
管理画面 Flask-Admin なし(自前か別途)
レート制限 Flask-Limiter slowapi

管理画面(Flask-Admin)はFlaskの独壇場。Djangoのadminほど高機能ではないが、モデルをCRUDできる管理画面が数行で作れる。FastAPIにはこれに相当するものがない。


パフォーマンス

一般的なベンチマーク結果のイメージ(環境によって変わるので参考程度)。

リクエスト/秒(JSON APIの場合)

Flask(同期)      :  約3,000〜5,000 req/s
Flask(async)     :  約4,000〜6,000 req/s
FastAPI(sync def):  約5,000〜8,000 req/s
FastAPI(async def):  約8,000〜15,000 req/s

I/Oバウンドな処理(DB・外部API)では非同期の効果が大きく出る。CPUバウンドな処理だけなら差は小さい。

ただし「どちらも現代のサービスで十分な性能」ではある。ボトルネックがフレームワークになることはほぼない。


個人的な使い分け基準

整理するとこうなった。

Flaskを選ぶとき

✓ HTMLテンプレートを使うWebアプリを作る
✓ 管理画面(Flask-Admin)が必要
✓ 小さなスクリプトやプロトタイプ
✓ チームがFlaskに慣れている
✓ 既存のFlaskプロジェクトを引き継いだ

FastAPIを選ぶとき

✓ JSON APIをメインに作る
✓ 型安全を最初から担保したい
✓ Swagger UIの自動生成が必要
✓ 非同期処理が必要(複数外部API呼び出しなど)
✓ フロントエンドをNext.jsなどで分離する構成
✓ OpenAPIスキーマをフロントチームと共有する

どちらでもよいとき

- REST APIの規模が小さい(エンドポイントが10個以下)
- チームの慣れで決める
- 個人開発でスピード重視

移行コスト

もし途中でFlask→FastAPIに移行したくなったら。

ルーティングの基本的な書き方は似ているので、コントローラー層の書き直しはそこまで大変ではない。一番コストがかかるのはバリデーション部分で、marshmallowなどを使っていた場合はPydanticモデルへの書き換えが必要になる。

逆にFastAPI→Flaskへの移行はほぼない(非同期コードの書き直しが発生するので)。


まとめ

観点 Flask FastAPI
向いている用途 WebアプリAP・管理画面・小規模API JSON API・型安全・非同期が必要な場合
バリデーション 別途ライブラリが必要 Pydantic標準
ドキュメント 設定が必要 自動生成
非同期 限定的 ネイティブ
管理画面 Flask-Adminが強力 ほぼなし
テンプレート Jinja2が自然 やや不自然
学習コスト 低い 中くらい

どちらが優れているという話ではなく、「何を作るか」で決まる。APIを作るなら今はFastAPIを選ぶ。HTMLも返す必要があるWebアプリやちょっとした管理ツールはFlaskが素直に書ける。

この判断基準を持ってから、フレームワーク選びで迷う時間がなくなった。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?