Flask互換性とエコシステム¶
higumaはFlaskに着想を得た独立したフレームワークです。Flask拡張をそのまま 読み込めるdrop-in replacementではありません。既存のFlaskアプリはWSGI mountで 動かし、新しい部分をhigumaのrouteで書く段階的な移行ができます。
既存のFlaskアプリを接続する¶
repository外では、自分のmodule名を指定してください。compatは任意のFlask 3.1系
検証用依存です。higuma単体のPython runtime依存は引き続き0です。
from flask import Flask, url_for
from higuma import Higuma
legacy = Flask(__name__)
@legacy.get("/hello/<name>")
def hello(name):
return {"name": name, "url": url_for("hello", name=name)}
app = Higuma(__name__)
app.mount_wsgi("/legacy", legacy)
/legacy/hello/%E6%97%A5%E6%9C%ACを開くと日本語のpath parameterを受け取れます。
Flask側のurl_forには/legacyが含まれ、Cookie、JSON body、redirectも渡されます。
mount内ではFlaskのrequest・sessionを使い、higumaの同名proxyと混同しないでください。
Flask拡張はFlask側へ初期化し、個別に動作を検証します。
higumaで使うFlask風API¶
| API | 動作 |
|---|---|
with app.app_context(): |
current_appとgを有効化。nested context終了時に外側を復元 |
g.name / g.get/pop/setdefault |
アプリコンテキスト単位の値。通常はリクエストごとに独立 |
app.extensions |
extensionのアプリ単位の保存先。リクエスト固有値は保存しない |
@app.teardown_appcontext |
context終了時に逆順実行。引数は未処理例外またはNone |
has_app_context() / has_request_context() |
contextの存在確認 |
session[key] |
SessionMiddlewareの署名Cookie sessionへのproxy |
flash(message, category="message") |
次のrequestへメッセージを保存 |
get_flashed_messages(with_categories=False, category_filter=()) |
sessionから一度取り出す。同一request内では結果を再取得可能 |
url_for(endpoint, **values) |
path値、余剰query値、list値、_anchor、_external、_scheme |
request.endpoint / request.blueprint |
選択されたendpointとBlueprint名。未選択時はNone |
app.register_error_handler(code_or_exception, handler) |
decoratorを使わないerror handler登録 |
render_template(...) |
app context内ではcontext processorを適用 |
response.headers |
読み書き・削除・get/popのheader名は大文字小文字を区別しない |
higuma run module:create_app() |
引数なしfactory。任意式の評価はしない |
相対endpointのurl_for(".detail", id=1)はBlueprint request内で使用できます。
余剰query値のNoneは省略します。_schemeは_external=Trueが必要です。
request外の外部URL生成にはapp.config["SERVER_NAME"]を設定してください。
外部URLにrequestのHostを使う場合、本番ではTrustedHostMiddlewareを設定します。
sessionとflashの例¶
import os
from higuma import (
CSRFProtection, Higuma, SessionMiddleware, csrf_token,
flash, get_flashed_messages, session,
)
app = Higuma(__name__)
app.add_middleware(SessionMiddleware, os.environ["HIGUMA_SECRET_KEY"])
app.add_middleware(CSRFProtection)
@app.get("/")
def index():
return {"messages": get_flashed_messages(), "csrf_token": csrf_token()}
@app.post("/save")
def save():
session["visits"] = session.get("visits", 0) + 1
flash("保存しました", "success")
return {"ok": True}
最初のGETでCookieとtokenを取得し、POSTのX-CSRF-Token headerへtokenを送ります。
Cookieは署名されますが暗号化されません。秘密情報や大きなflash本文を保存しないでください。
本番HTTPSではSessionMiddleware(..., secure=True)を設定します。
実行例はexamples/flask_compat.pyです。
明示的な境界¶
- Flaskのsignals、Werkzeug routing、Flask CLI extension、
test_request_contextなどの 完全互換は提供しません。Flask extensionのinit_app(higuma_app)動作は保証しません。 - Template engineはMiniJinjaです。Flask/Jinja2の全filterやPython callable globalは 提供しません。URLやflashはviewで生成しtemplateのcontextへ渡します。
- WSGI/ASGI mountはHTTP request/responseをbufferします。mount内のSSE・無期限stream、 WebSocket、ASGI lifespanの代替ではありません。streamはhiguma native APIを使います。
- ASGIはdecoded
pathと元のpercent-encodedraw_pathを渡します。 - WSGI header正規化による衝突を避けるため、名前に
_を含む入力headerは破棄します。 - teardownはdispatch/context終了時に実行されます。遅延streamやbackground taskで
teardown済みの
g上のDB接続などを使わず、その処理の中でresourceを開いてください。 - RateLimitMiddlewareはprocess内のみの制限です。
max_keys到達時は新しいidentityで 共有枠を使い、有効な履歴は追い出しません。共有枠の履歴失効までは個別枠へ移行しません。 混雑時には新規利用者が同じ制限枠になります。複数workerの一括制限はproxy等で行います。
仕様の参考: Flask application context、 WSGI PEP 3333、 ASGI HTTP scope。