(第71回)Python mini Hack-a-thonで行った内容の個人的な備忘録です。
書いていたらついつい長くなってしまったので、何回かに分けます。
このイベント、Hack-a-thonと書いていますが、各々が好きなことをやるイベントです。 今回は、先日Qiitaで見つけた、Falconという速いらしいWebフレームワークのソースコードをPythonの勉強がてら眺めてみました。
Falconとは
情報はこちらにまとまっています。
ざっと見たところ下記のような特徴があるようです。
- ミニマルで速いWSGIアプリケーション
- ベンチマークはこちら
 
 - HTTP and the REST architectural styleな設計
- Resourceクラスを定義して
on_getやon_postを実装する 
 - Resourceクラスを定義して
 - APIサーバー向けに絞った機能だけを提供(テンプレート機能や認証などはなし)
 - テストコードとドキュメントがしっかりある(コメントも豊富)
 
ついでにソースコード(*.py)のファイル数や行数なども調べてみました。
ちょっとしたPythonの勉強にはちょうどいいサイズ感ではないでしょうか。
[alpaca]~/github/falcon/falcon % pwd
/Users/rhoboro/github/falcon/falcon
# ソースコードは55ファイル
[alpaca]~/github/falcon/falcon % find . -name "*.py" | wc
      55      55    1181
# トータルで9500行程度。一番大きなファイルでも1351行。
[alpaca]~/github/falcon/falcon % find . -name "*.py" | xargs wc | sort -r | head
    9439   39313  343961 total
    1351    7370   60395 ./errors.py
    1321    5517   50907 ./request.py
     718    3271   27566 ./response.py
     683    2913   28151 ./api.py
     652    2664   24076 ./testing/client.py
     457    2120   16512 ./util/uri.py
     363    1394   13628 ./routing/compiled.py
     334     837    9109 ./bench/bench.py
     318    1144    9566 ./util/misc.py
ソースコードを読んでいく
ざっくりと概要がわかったところで、下記の流れでソースコードを読んでみました。
- QuickstartとTutorialを読んでざっくりと使い方を知る
 - エントリポイントがどこかを調べる
 - そこからどういう処理が行われているかを調べる
 - せっかくなので、速い理由になってそうなところを調べる
 
エントリポイント
Falconを利用したアプリケーションの最小構成は、ドキュメントにあるとおり。
import falcon
api = application = falcon.API()
こちらのfalcon.API()がWSGIアプリケーションになります。
でもほぼろは「WSGIアプリケーションとは」をそもそもちゃんと理解していなかったので、WSGIについても調べました。
Python Web Server Gateway Interface (WSGI)
声に出すときは「うぃすぎー」「うぃずぎー」あたりであれば恥ずかしくないです。
WSGIの詳細はPEP333をご覧ください。(どうしても日本語でという方はWikipediaを)
とても簡単にいうと、WebサーバーとWebアプリケーションを繋ぐ部分(インターフェース)の仕様です。
お互いがWSGIに準拠していれば、Webサーバを変えずにWebアプリケーション側のフレームワークを変えたりできるという利点があります。
WSGI準拠のWebサーバーとしては、gunicornやuWSGIが有名でしょうか。
Webアプリケーション側だとDjangoやFlask、Pyramid、Bottleなど有名どころはほぼ対応しています。
で、WSGIアプリケーションがやらないといけないことはざっくりとこんな感じです。
- Webサーバーにリクエストが来ると、WebアプリケーションのCallableなオブジェクトが呼び出される(falcon.API())
 - このとき、Callableなオブジェクトにはパラメータとして、いろいろな環境変数とstart_responseが渡される
 - Webアプリケーションは、(必要な処理を行った後)パラメータで渡された
start_responseを呼び出し、ステータスコードとヘッダーを渡す - その後、iterableなオブジェクトを返り値として返す
 
Webサーバーはこれらの情報からレスポンスを生成し、クライアントに返すという流れになっています。
falcon.API()
Falconでエントリポイントとなっているfalcon.API()のソースコードはfalcon/api.pyです。
class API(object):
    ~省略~
    def __call__(self, env, start_response):  # noqa: C901
    ~省略~
        # Return the response per the WSGI spec
        start_response(resp.status, headers)
        return body
__call__メソッドは、オブジェクトを関数のように呼び出し可能なオブジェクトにしてくれる特殊メソッドです。
WSGIサーバーにAPIクラスのインスタンスを渡し、リクエストがきた際にenv, start_responseをパラメータとしてこのインスタンスを呼び出してもらいます。
そして、ごにょごにょと処理を行った後、start_response(resp.status, headers)でステータスコードとヘッダーを渡し、body(これはiterableなオブジェクト)を返しています。
すべてのリクエストでこの処理が毎回行われることになります。
ちゃんと上述したWSGIアプリケーションに沿った動きになっていますね!
次回に続く
WSGIの説明しかしてない気もしますが、今回はここまで(笑)
次回はもう少しソースコードを読んでいて気になったところをピックアップするつもりです。
HTTPはステートレスなものなので、いまの状態などを意識しないでいいのは普段モバイル開発をしている身としては楽ですね!
スマホアプリはそれ自体がステートフルなものなので、常に状態を気にせずにはいられない...orz