Pure Python FastAPI from Scratchの再実装なし
Ethan Miller
Product Engineer · Leapcell

FastAPIのようなルーティングスキームをWSGIから実装する
PythonのWeb開発の分野では、FastAPIはその効率的で簡潔なルーティング設計と、その強力な機能性によって、開発者に広く支持されています。FastAPIは、従来のWSGI(Web Server Gateway Interface)とは異なるASGI(Asynchronous Server Gateway Interface)プロトコルに基づいて構築されています。この記事では、WSGIから始めてFastAPIに似たルーティングスキームを実装する方法を探求し、WSGIやUvicornなどの主要な概念とそれらの相互関係を深く分析します。
I. WSGI、ASGI、およびUvicornの概念分析
1.1 WSGI:Web Server Gateway Interface
WSGIは、PythonのWeb開発における標準インターフェースであり、WebサーバーとPython Webアプリケーション間の通信仕様を定義します。その登場は、異なるWebサーバーとWebフレームワーク間の互換性の問題を解決し、開発者が連携できないことを心配せずに、Webサーバーとフレームワークを自由に選択できるようにします。
WSGIは、Webアプリケーションを、リクエスト情報を含む辞書(environ
)と、レスポンスステータスコードとヘッダー情報を送信するためのコールバック関数(start_response
)の2つのパラメータを受け入れる呼び出し可能なオブジェクトとして抽象化します。たとえば、単純なWSGIアプリケーションは次のように記述できます。
def simple_app(environ, start_response): status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return [b'Hello, World!']
この例では、environ
には、リクエストメソッド、URL、HTTPヘッダーなどのリクエスト関連情報が含まれています。 start_response
関数は、レスポンスステータスコードとヘッダー情報を設定するために使用されます。関数の戻り値は、レスポンスボディです。
1.2 ASGI:Asynchronous Server Gateway Interface
Pythonでの非同期プログラミングの台頭、特にasyncio
ライブラリの普及に伴い、従来のWSGIは非同期I/O操作に対応できなくなりました。 ASGIが誕生しました。 WSGIの拡張として、同期アプリケーションをサポートするだけでなく、非同期リクエストを効率的に処理することもでき、最新のWebアプリケーションのハイパフォーマンスとハイコンカレンシーのニーズを満たします。
ASGIは、サーバーとアプリケーション間の通信プロトコルも定義しますが、そのアプリケーションの呼び出し可能なオブジェクトは非同期メソッドをサポートします。単純なASGIアプリケーションの例を次に示します。
async def simple_asgi_app(scope, receive, send): assert scope['type'] == 'http' await send({ 'type': 'http.response.start', 'status': 200, 'headers': [ (b'content-type', b'text/plain') ] }) await send({ 'type': 'http.response.body', 'body': b'Hello, ASGI!' })
ここで、scope
には、リクエストタイプ(http
など)などの情報が含まれています。 receive
は、クライアントから送信されたデータを受信するために使用されます。 send
は、レスポンスデータをクライアントに送信するために使用され、プロセス全体が非同期操作をサポートします。
1.3 Uvicorn:ASGIサーバー
Uvicornは、Pythonベースの高性能ASGIサーバーであり、ASGIアプリケーションを実行でき、WSGIアプリケーションとも互換性があります。 Uvicornは、uvloop
やhttptools
などのライブラリを使用して、効率的なイベントループとHTTP解析を実装し、ASGIの非同期の利点を最大限に活用し、優れたパフォーマンスを提供します。
実際の開発では、Uvicornを使用してASGIまたはWSGIアプリケーションを起動できます。たとえば、上記のASGIアプリケーションを起動するには、次のようにします。
uvicorn main:app --reload
ここで、main
はアプリケーションコードを含むPythonモジュールの名前、app
はモジュールで定義されたASGIアプリケーションオブジェクト、--reload
パラメーターは、コードが変更されたときにアプリケーションを自動的にリロードするために使用されます。
II. FastAPIのようなルーティングスキームをWSGIから実装する
2.1 ルーティングシステムの基本原則
FastAPIのルーティングシステムは、デコレーターを介して関数を特定のURLパスにバインドします。パスに一致するリクエストを受信すると、対応する処理関数が呼び出され、応答が返されます。 WSGIで同様のルーティングシステムを実装する際の中心的な考え方は、リクエストのURLパスに基づいて対応する処理関数を見つけ、それを呼び出して応答を生成することです。
ルーティングテーブルを定義して、URLパスと処理関数の間のマッピングを格納できます。リクエストが到着すると、一致するパスがルーティングテーブルに見つかり、対応する処理関数が呼び出されて応答が生成されます。
2.2 簡単なWSGIルーティングシステムの実装
以下に、FastAPIのルーティング機能をシミュレートするために、簡単なWSGIルーティングシステムを段階的に実装します。
まず、空のルーティングテーブルを定義します。
route_table = {}
次に、関数をURLパスにバインドし、ルーティングテーブルに追加するためのデコレーターを作成します。
def route(path): def decorator(func): route_table[path] = func return func return decorator
次に、リクエストパスに基づいて対応する処理関数を見つけて呼び出すためのWSGIアプリケーションを実装します。
def wsgi_app(environ, start_response): path = environ.get('PATH_INFO', '/') if path in route_table: response_body = route_table[path]() status = '200 OK' else: response_body = [b'404 Not Found'] status = '404 Not Found' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return response_body
これで、定義されたルーティングデコレーターを使用して処理関数を定義できます。
@route('/') def index(): return [b'Welcome to the index page!'] @route('/about') def about(): return [b'This is the about page.']
最後に、Uvicornを使用してこのWSGIアプリケーションを実行します。
uvicorn main:wsgi_app --reload
上記の手順により、さまざまなURLパスに応じて対応するコンテンツを返すことができる簡単なWSGIルーティングシステムを実装し、FastAPIのルーティング機能を最初にシミュレートしました。
2.3 ルーティングシステムの改善
上記のルーティングシステムは基本的なバージョンにすぎず、多くの欠点があります。たとえば、動的ルーティング(パラメータ化されたパスなど)またはリクエストメソッドの処理はサポートされていません。以下に、それを改善します。
動的ルーティングのサポート
動的ルーティングをサポートするには、正規表現を使用してパスを照合し、パスからパラメーターを抽出できます。 re
モジュールをインポートし、ルーティングテーブルとルーティングデコレーターを変更します。
import re route_table = {} def route(path): def decorator(func): route_table[path] = func return func return decorator def dynamic_route(path_pattern): def decorator(func): route_table[path_pattern] = func return func return decorator
同時に、動的ルーティングを処理するためにWSGIアプリケーションを変更します。
def wsgi_app(environ, start_response): path = environ.get('PATH_INFO', '/') for pattern, handler in route_table.items(): if isinstance(pattern, str): if path == pattern: response_body = handler() status = '200 OK' break else: match = re.match(pattern, path) if match: args = match.groups() response_body = handler(*args) status = '200 OK' break else: response_body = [b'404 Not Found'] status = '404 Not Found' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return response_body
これで、動的ルーティング処理関数を定義できます。
@dynamic_route(r'/user/(\d+)') def user_detail(user_id): return [f'User {user_id} detail page.'.encode()]
リクエストメソッドのサポート
さまざまなリクエストメソッド(GETやPOSTなど)をサポートするには、ルーティングテーブルに、各パスに対応するさまざまなリクエストメソッドの処理関数を格納できます。ルーティングテーブルとルーティングデコレーターを次のように変更します。
route_table = {} def route(path, methods=['GET']): def decorator(func): if path not in route_table: route_table[path] = {} for method in methods: route_table[path][method] = func return func return decorator
同時に、リクエストメソッドに基づいて対応する処理関数を呼び出すために、WSGIアプリケーションを変更します。
def wsgi_app(environ, start_response): path = environ.get('PATH_INFO', '/') method = environ.get('REQUEST_METHOD', 'GET') if path in route_table and method in route_table[path]: response_body = route_table[path][method]() status = '200 OK' else: response_body = [b'404 Not Found'] status = '404 Not Found' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return response_body
これで、さまざまなリクエストメソッドをサポートする処理関数を定義できます。
@route('/login', methods=['GET', 'POST']) def login(): return [b'Login page.']
上記の改善により、WSGIルーティングシステムはより完全になり、動的ルーティングとさまざまなリクエストメソッドをサポートできるようになり、FastAPIのルーティング機能にさらに近づきます。
III. まとめと展望
この記事では、WSGIの基本概念から始めて、ASGIとUvicornに関する関連知識を紹介し、簡単なWSGIルーティングシステムを段階的に実装することにより、FastAPIのルーティング機能をシミュレートします。このプロセスを通じて、Webサーバーとアプリケーション間の通信プロトコル、およびルーティングシステムの中核となる原則について深く理解することができました。
実装したWSGIルーティングシステムはFastAPIとはまだかけ離れていますが、ルーティングシステムの実装を理解するための明確なアイデアを提供します。将来的には、リクエストボディの解析やレスポンスボディのシリアル化などの機能を追加して、このルーティングシステムをさらに改善し、実際の制作環境で使用されるWebフレームワークに近づけることができます。同時に、このルーティングシステムをASGI環境に拡張して、非同期プログラミングの利点を最大限に活用し、アプリケーションのパフォーマンスと同時実行処理機能を向上させる方法も検討できます。
上記の内容は、WSGIを使用してルーティングスキームを実装するプロセスを詳しく説明しています。特定の部分をもっと深く掘り下げたり、新しい機能を追加したりする必要があると思われる場合は、お気軽にお知らせください。
Leapcell:最高のサーバーレスWebホスティング
Pythonサービスのデプロイに最適なプラットフォームとして推奨:Leapcell
🚀 お気に入りの言語で構築
JavaScript、Python、Go、またはRustで簡単に開発できます。
🌍 無制限のプロジェクトを無料でデプロイ
使用量に応じてのみお支払いください。リクエストも料金もかかりません。
⚡ 従量課金制、隠れたコストなし
アイドル料金はなく、シームレスなスケーラビリティだけです。
🔹 Twitterでフォローしてください:@LeapcellHQ