Python Falcon ちょっと本気のクイックスタート

  • 42
    Like
  • 0
    Comment
More than 1 year has passed since last update.

序章

最近 API のプロトタイピングの機会が増えて 「やっぱ Python かっこいいよね」 という自分の中の風潮もあり、
この際、Python を手に馴染ませたいなということで、良さそうなフレームワークを模索してました
Django でも良かったんだけど Django REST Framework とか面倒そうだし、
そもそも作って動かしてすぐ捨てるかもしれないので重厚なのは嫌だなということで、他に調べてみると、Flask とか Bottle とか Pyramid とかとか・・

2016年大注目のPython!WEBフレームワーク3つを徹底比較

Python 界隈では Django じゃないなら Flask なんだろうけど、
性格上、トンがりたいので、さらに調べて見つけたのが Falcon (Phalcon じゃないよ)

Falconで光速のWeb APIサーバーを構築する - Qiita
Python+FalconでWebAPI - Qiita

さっそく調べると、やっぱ情報あんまないのね
公式ドキュメントを見たほうが早そう、ということで見様見真似で実装してみたら、まぁ シンプル!
ということで 「最低限これくらい覚えとけば、プロトタイプから小規模開発くらいまでカバー出来んじゃね」 というコードを整理して公開します

実際のソースコードはこちら (↓)
https://github.com/yohjizzz/python-falcon-quickstart

前提

Python == 3.5.1
Falcom == 1.0.0rc2 (当初は 0.3.0 使ってたけど 1.0.0rc2 の存在に気づき・・)

ソースコード

resources.py と extension.py の 2つだけ!

resources.py
import .. (省略)

@falcon.before(extension.before_resource)
@falcon.after(extension.after_resource)
class BookResource(object):

    def on_get(self, req, resp, isbn):
        pass  # (省略)

    def on_post(self, req, resp):
        pass  # (省略)

    def on_put(self, req, resp, isbn):
        pass  # (省略)

    def on_delete(self, req, resp, isbn):
        pass  # (省略)

app = falcon.API(middleware=extension.ExtensionComponent())
app.add_route("/books/{isbn}", BookResource())

if __name__ == "__main__":
    from wsgiref import simple_server

    httpd = simple_server.make_server("127.0.0.1", 8008, app)
    httpd.serve_forever()

# Or "gunicorn resources:app --reload"
extension.py
class ExtensionComponent(object):

    def process_request(self, req, resp):
        print("middleware: process before routing")

    def process_resource(self, req, resp, resource, param):
        print("middleware: process before resource", resource)

    def process_response(self, req, resp, resource):
        print("middleware: process before response", resource)

def before_resource(req, resp, resource, params):
    print("hook: process before resource", resource)


def after_resource(req, resp, resource):
    print("hook: process after resource", resource)

解説

1. Resource class

任意のクラス (上記の例だと BookResource) に "on_{HTTPメソッド}" という命名に従い、メソッドを用意して、
falcon.API.add_route で URL とリソースクラスを紐づけます

紐付ける URL に動的な要素がないのであれば、

    def on_get(self, req, resp):  # req -> falcon.Request, resp -> falcon.Response

で ok、動的な要素を含むのであれば、

    def on_get(self, req, resp, isbn):  # isbn -> add_route("/books/{isbn}", ...) の {isbn} の値!

とメソッドの引数に指定することで取得できます

2. Hooks

任意のリソースクラスに前後処理を組み込むことも簡単です
対象のリソースクラス または メソッドに対して、以下のデコレーターを使ってファンクションを指定するだけです

@falcon.before(extension.before_resource)  # on_**** の直前に extension.py の before_resource がコールされる
@falcon.after(extension.after_resource)  # on_**** の直後に extension.py の after_resource がコールされる
class BookResource(object):

上記ソースコードの例では、クラスに before と after の両方を指定してるので on_**** すべてに適応されます

3. Middleware

Hooks (@falcon.before, after) とは異なり、
アプリケーション全体の特定のフェーズに対して処理を組み込む場合は Middleware という仕組みを利用します
任意のクラスを用意、以下のメソッドを実装することで、それぞれのフェーズでコールされます

    def process_request(self, req, resp):
        pass  # リクエスト受信後  ※リソースクラスが見つからなくてもコールされる

    def process_resource(self, req, resp, resource, param):
        pass  # リクエスト URL に対するリソースクラス実行前

    def process_response(self, req, resp, resource):
        pass  # レスポンス送信前  ※リソースクラスが見つからなくてもコールされる

Middleware と Hooks が指定されている場合、処理シーケンスは以下のようになります

  1. Middleware's process_request
  2. Middleware's process_resource
  3. Hook's before
  4. Resource's on_****
  5. Hook's after
  6. Middleware's process_response

※リクエストされた URL に対するリソースクラスが見つからなければ 2, 3, 4, 5 はスキップされます

4. Read/Write

リクエストボディを読み込んで JSON を解析するのは これ (↓)

    body = json.loads(req.stream.read().decode('utf-8'))  # req.stream.read() で取得した bytes を文字列にデコードしておしまい

レスポンスに json を流し込みたければ これ (↓)

    resp.body = json.dumps(json_data)
    resp.status = falcon.HTTP_200

5. Usage

python v3.5.1 が入ってる前提 (virtualenv とかも必要に応じて・・) で、

$ pip install falcon==1.0.0rc2
$ python resources.py

最後に・・

Falcon がこれからどうなるのか、わかりません
ざっと調べる限り、人気も情報量も Flask や Bottle に大差をつけられてる感じがする...

簡易なプロトを Falcon で実装して、あとから Django や Flask に置き換えてもいいわけなので、
せっかく出会った彼と、しばらく一緒に歩んでみたいと思います

シンプルで直感的、いいよ Falcon :kissing_heart: