付録D 読解ガイド
本書を通じて、HTTP リクエストがサーバに届いてからレスポンスが返るまでの流れを追ってきました。 フレームワークの内部動作を本当に理解するには、最終的にソースコードを読むことが最も確実な方法です。 しかし、大規模なコードベースをいきなり開いても、どこから手をつければよいか分からず挫折しがちです。
本付録では、本書で扱った 3 つのコードベースについて、「最初に読むべきファイル」と「読み進めるための道筋」を紹介します。
Tip
ソースコードを読むときは、「全部理解しよう」と焦らないことが大切です。 まずは「リクエストがどう処理されるか」という一本の流れだけを追うことから始めましょう。
Django のソースをどこから読むか
Django のソースコードは GitHub の django/django リポジトリにあり、主要なコードは django/ ディレクトリ以下に配置されています。
全体は巨大ですが、本書の内容に沿って読むなら、入口は明確です。
起点:リクエストの入口
最初に開くべきファイルは django/core/handlers/wsgi.py です。
ここに WSGIHandler クラスがあり、WSGI サーバから environ と start_response を受け取って Django の処理に橋渡しする部分になっています。
__call__ メソッドがリクエストの入口であり、以下の流れが数十行で読み取れます。
WSGIRequestオブジェクトを生成するself.get_response(request)を呼び出すレスポンスを返却する
本書の 2 章・3 章で解説した「WSGI とフレームワークの接続点」がまさにここです。
注釈
ASGI 側を読みたい場合は、django/core/handlers/asgi.py の ASGIHandler が対応するクラスです。
scope, receive, send を受け取る構造になっており、WSGI 版と並べて読むと、同じ処理がどのように非同期化されているかが明確に分かります。
次に読む:ミドルウェアチェーン
WSGIHandler.get_response を追うと、django/core/handlers/base.py の BaseHandler にたどり着きます。
ここで押さえるべきメソッドは 2 つです。
メソッド |
役割 |
|---|---|
|
|
|
URL 解決とビュー呼び出しの核心部分 |
本書の 8 章で解説したミドルウェアの「玉ねぎ構造」が、ここで実装として確認できます。
個別のミドルウェアを読むなら、django/middleware/security.py(SecurityMiddleware)が最も短く読みやすいファイルです。
SECURE_SSL_REDIRECT や SECURE_HSTS_SECONDS の処理が数十行で実装されており、14 章で扱ったセキュリティ設定がどう動作するかを具体的に理解できます。
django/middleware/csrf.py はより複雑ですが、CSRF トークンの生成・検証の全工程が 1 ファイルに収まっているため、14-5 章の CSRF の理解を深めるのに最適です。
URL 解決とビュー呼び出し
django/urls/resolvers.py には URLResolver と URLPattern があり、resolve メソッドがリクエストパスをビュー関数にマッピングする処理を担っています。
正規表現や path コンバータがどう評価されるかをステップ実行で追うと、URL 設計の制約や優先順位が体感できます。
リクエスト・レスポンスオブジェクト
django/http/request.py の HttpRequest と QueryDict、django/http/response.py の HttpResponse と JsonResponse は、本書の 4 章・5 章に直結するファイルです。
QueryDict が __getitem__ で最後の値だけ返し、getlist で全値を返す仕組みは、ソースを読むと「なぜそうなっているのか」が分かります。
ORM を読むなら
ORM に踏み込む場合は django/db/models/query.py の QuerySet クラスが起点です。
filter, exclude, annotate などのメソッドが内部的に Query オブジェクト(django/db/models/sql/query.py)を組み立てていく過程が読めます。
注意
ORM のコードは複雑度が高いため、最初から全部を読もうとすると挫折しやすいです。
まずは QuerySet.__iter__ を追って「SQL がいつ発行されるか」を確認するところから始めることをおすすめします。
読む順序のまとめ
Django を読む際は、以下の順序がおすすめです。
django/core/handlers/wsgi.pyのWSGIHandler.__call__でリクエストの入口を押さえるdjango/core/handlers/base.pyのBaseHandler.load_middlewareと_get_responseでミドルウェアと URL 解決の流れを理解するdjango/middleware/security.pyで短いミドルウェアの実装を読む
この 3 ステップで、Django がリクエストを受け取ってからビューに到達するまでの全景が見えてきます。
FastAPI / Starlette のソースをどこから読むか
FastAPI は Starlette の上に構築されているため、実行時の HTTP 処理の大部分は Starlette のコードが担っています。 FastAPI 固有のコードは主に以下の部分に集中しています。
ルーティングの拡張
依存性注入
バリデーション(Pydantic 連携)
OpenAPI スキーマ生成
重要
FastAPI のソースを読む際は、「いま読んでいるのは FastAPI の層か Starlette の層か」を常に意識することが重要です。 この 2 層を混同すると、どこで何が起きているか分からなくなりがちです。
起点:ASGI アプリケーションの入口
Starlette 側の入口は starlette/applications.py の Starlette クラスです。
__call__ メソッドが scope, receive, send を受け取り、ミドルウェアスタック経由でルーティングに渡す流れが読めます。
FastAPI 側では fastapi/applications.py の FastAPI クラスが Starlette を継承しており、__init__ で追加のセットアップ(ルーターの差し替え、OpenAPI 設定など)を行っています。ただし __call__ 自体は Starlette のものがそのまま使われています。
ルーティング
Starlette のルーティングは starlette/routing.py にあり、以下の 3 クラスが中心です。
クラス |
役割 |
|---|---|
|
1 つのパスとハンドラの対応を表す |
|
複数の |
|
パスのプレフィックスで別の |
Router.route メソッド(デコレータ)が Route オブジェクトを生成し、Router.__call__ でリクエストパスとのマッチングを行います。
マッチングのロジックは Route.matches メソッドに集約されており、パスパラメータの抽出({item_id} 形式)もここで処理されます。
FastAPI は fastapi/routing.py で APIRoute と APIRouter を定義し、Starlette の Route / Router を拡張しています。
APIRoute の get_route_handler メソッドが、リクエストのバリデーション・依存性注入・レスポンスのシリアライズを組み込んだハンドラを生成する箇所です。
FastAPI の「魔法」の多くはここに集約されています。
リクエスト・レスポンス
starlette/requests.py の Request クラスは、ASGI の scope をラップして以下のようなインターフェースを提供します。
request.method— HTTP メソッドrequest.url— リクエスト URLrequest.headers— ヘッダー情報await request.json()— JSON ボディの取得
付録 B で示した生の scope / receive 操作がどのように抽象化されているかが直接読めます。
Tip
特に await request.body() の実装は読む価値があります。
receive のチャンク受信をキャッシュする仕組みが分かり、「ボディは一度しか消費できない」という制約がどのように解決されているかが理解できます。
starlette/responses.py には Response, JSONResponse, HTMLResponse, StreamingResponse などがあり、いずれも __call__ メソッドで send を呼び出してレスポンスを送信しています。
StreamingResponse の実装は、"more_body": True を使った段階的送信の実例として読む価値があります。
ミドルウェア
starlette/middleware ディレクトリに各種ミドルウェアがあります。
starlette/middleware/cors.py(CORSMiddleware)は、本書の 14-8 章で扱った CORS の仕組みが実装レベルで確認できるファイルです。
以下のような処理が読めます。
プリフライトリクエスト(
OPTIONS)の処理Access-Control-Allow-Originヘッダーの生成ロジックワイルドカード
*とallow_credentialsの排他制御
依存性注入
FastAPI の依存性注入は fastapi/dependencies/utils.py と fastapi/dependencies/models.py に実装されています。
get_dependant 関数がエンドポイントの型ヒントを解析し、Dependant オブジェクトのツリーを構築する過程が読めます。
難易度について
class: caution
このコードはメタプログラミングが多用されており、難度は高めです。
ただし、Depends() がどのように解決されるかを理解するうえで避けて通れない部分でもあります。
最初は「大まかな流れをつかむ」ことを目標に、細部は後回しにしてもよいでしょう。
読む順序のまとめ
FastAPI / Starlette を読む際は、以下の順序がおすすめです。
starlette/applications.pyのStarlette.__call__で ASGI の入口を押さえるstarlette/routing.pyのRouter.__call__とRoute.matchesでルーティングの仕組みを理解するstarlette/requests.pyのRequestクラスでscope/receiveの抽象化を確認するfastapi/routing.pyのAPIRoute.get_route_handlerで FastAPI 固有の拡張を読む
Werkzeug のソースをどこから読むか
Werkzeug は Flask の基盤となっている WSGI ユーティリティライブラリです。 Flask 自体のコードは比較的薄く、HTTP の処理やリクエスト/レスポンスのパース、URL ルーティング、開発サーバなど、重い処理の多くは Werkzeug が担っています。
Flask のソースを読みたい場合も、最終的に Werkzeug のコードにたどり着くことが多いため、Werkzeug を直接読む技術は Flask 理解の土台となります。
起点:リクエストとレスポンス
最初に読むべきファイルは werkzeug/wrappers/request.py と werkzeug/wrappers/response.py です。
Request クラスは WSGI の environ 辞書をラップし、以下のような使い慣れたインターフェースを提供します。
request.method— HTTP メソッドrequest.args— クエリパラメータrequest.form— POST データrequest.headers— ヘッダー情報
Request クラスの中で特に読む価値があるのは args プロパティの実装です。
environ["QUERY_STRING"] を MultiDict にパースする過程が追えます。
注釈
MultiDict(werkzeug/datastructures/structures.py)は Django の QueryDict に相当するデータ構造です。
同一キーに複数の値が送られてきた場合にどう扱うかという設計思想が読み取れます。
たとえば、フォームで同じ名前のチェックボックスが複数ある場合などがこれにあたります。
Response クラスは __call__(environ, start_response) メソッドを持っており、それ自体が WSGI アプリケーションとして振る舞えるという設計になっています。
Content-Type や Content-Length の自動設定、Set-Cookie ヘッダーの構築などがこのクラスに集約されています。
URL ルーティング
werkzeug/routing/map.py の Map クラスと werkzeug/routing/rules.py の Rule クラスが URL ルーティングの中心です。
クラス/メソッド |
役割 |
|---|---|
|
全 URL ルールを管理するコンテナ |
|
個別のパスパターンと HTTP メソッドの対応を表す |
|
リクエスト情報にバインドした |
|
パスと HTTP メソッドに基づいてルールをマッチングする |
Flask の @app.route("/users/<int:user_id>") がどう動くかを知りたければ、以下を順番に読むと全体像がつながります。
Rule.__init__でパスパラメータがどうパースされるかwerkzeug/routing/converters.pyのIntegerConverterやUnicodeConverterがどう型変換するか
開発サーバ
werkzeug/serving.py は、Flask の app.run() で起動する開発サーバの実装です。
Python 標準ライブラリの http.server をベースに、マルチスレッド対応やオートリロード機能を追加しています。
警告
本書の 14-7 章で「開発サーバを本番利用してはいけない」と述べましたが、その理由がソースレベルで確認できます。 以下のような本番には不適切な特性がコードから読み取れます。
シングルスレッドのリクエスト処理
デバッグ用のトレースバック表示(エラー内容がブラウザに丸見えになる)
TLS 対応の簡素さ
run_simple 関数を追うと、リクエストが到着してからレスポンスが返るまでの全工程が 1 ファイルで完結しており、WSGI サーバの最小実装として非常に教育的です。
付録 A で書いた最小 WSGI アプリが、実際のサーバ上でどのように呼ばれるかを具体的に理解できます。
デバッガ
werkzeug/debug/__init__.py の DebuggedApplication は、例外発生時にブラウザ上でインタラクティブな Python コンソールを提供する WSGI ミドルウェアです。
これは開発時には便利ですが、本番で有効にすると任意のコード実行が可能になるため、重大な脆弱性となります。
このミドルウェアのコードを読むと、「ミドルウェアで例外をキャッチし、通常とは異なるレスポンスを返す」というパターンの実例として理解でき、同時にセキュリティリスクの具体性も体感できます。
読む順序のまとめ
Werkzeug を読む際は、以下の順序がおすすめです。
werkzeug/wrappers/request.pyのRequestクラスでenvironの抽象化を理解するwerkzeug/routing/rules.pyのRuleとwerkzeug/routing/map.pyのMapで URL ルーティングの仕組みを把握するwerkzeug/serving.pyのrun_simpleで開発サーバの全体像を確認する
この 3 ステップを経ると、Flask のコード(flask/app.py の Flask クラス)は、これらの Werkzeug コンポーネントを組み立てる薄いレイヤーとして読めるようになります。
ソースコードを読むための実践的なテクニック
3 つのコードベースに共通する、ソース読解の実践的なアプローチを最後に紹介します。
1. リクエストの入口から追う
どのフレームワークも __call__ メソッドが入口です。そこから print や breakpoint() を挟みながら実行フローを追うのが最も確実な方法です。
python -m pdb や IDE のデバッガで、実際にリクエストを送りながらステップ実行すると、呼び出し順序とデータの変化が手に取るように分かります。
2. git log と git blame を活用する
あるコードがなぜそう書かれているかは、コミットメッセージや関連する Issue・PR に書かれていることが多いです。 特にセキュリティ修正のコミットは脆弱性の具体的な攻撃手法と対策が記録されており、14 章の内容を深く理解する助けになります。
3. テストコードを先に読む
テストはそのコードが「何をすべきか」を宣言的に示しています。実装コードを読む前にテストを読むと、期待される振る舞いが把握できます。
フレームワーク |
テストの場所 |
|---|---|
Django |
|
Starlette |
|
Werkzeug |
|
重要
ソースコードを読む力は一朝一夕には身につきません。 しかし、本書で得た HTTP・WSGI/ASGI・ミドルウェア・セキュリティの知識があれば、コードの意図を推測するための土台は十分に整っています。 まずは上記の「最初に読むべきファイル」を 1 つ開くところから始めてみてください。