webフレームワークを作ってる話 #osakapy
TRANSCRIPT
WAFをつくってる話
大阪Pythonユーザの集まり 2016/04
MASASHI SHIBATA! c_bata_
@c_bata_
django / flask / pandas明石高専
話すこと
1. WSGIの話とか
2. WAFに欲しい機能を考える
3. Kobinの紹介
4. Kobinにおける取り組み
WSGI Web Server Gateway Interface
WSGI??
• Pythonで作るWebアプリケーションの実装方法の標準化仕様
• 実装を切り離して、WebサーバとWAFの組み合わせを柔軟に
https://www.python.org/dev/peps/pep-3333/
https://www.python.org/dev/peps/pep-333/
WSGI v1.0.1 (PEP3333)
• 2つの引数を持った呼び出し可能なオブジェクト
• 第2引数として渡されたオブジェクトにHTTPステータスコードと (header_name, header_value) タプルのリストを渡す
• 返り値はバイト文字列を yield する iterableなオブジェクト
https://www.python.org/dev/peps/pep-3333/
WSGI v1.0.1 (PEP3333)
def app(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return [b"Hello World"]
• 2つの引数を持った呼び出し可能なオブジェクト
https://www.python.org/dev/peps/pep-3333/
WSGI v1.0.1 (PEP3333)
def app(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return [b"Hello World"]
• 第2引数として渡されたオブジェクトの引数はHTTPステータスコードと(header_name, header_value) タプルのリスト
https://www.python.org/dev/peps/pep-3333/
WSGI v1.0.1 (PEP3333)
def app(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return [b"Hello World"]
• バイト文字列を yield する iterable を返さなければならない
• 例えば、バイト文字列のリストを返すようにする
https://www.python.org/dev/peps/pep-3333/
Hello World with gunicorn
$ gunicorn -w 1 main:app[2016-04-15 10:17:00 +0900] [1873] [INFO] Starting gunicorn 19.4.5[2016-04-15 10:17:00 +0900] [1873] [INFO] Listening at: http://127.0.0.1:8000 (1873)[2016-04-15 10:17:00 +0900] [1873] [INFO] Using worker: sync[2016-04-15 10:17:00 +0900] [1878] [INFO] Booting worker with pid: 1878^C[2016-04-15 10:17:08 +0900] [1873] [INFO] Handling signal: int[2016-04-15 10:17:08 +0900] [1878] [INFO] Worker exiting (pid: 1878)[2016-04-15 10:17:08 +0900] [1873] [INFO] Shutting down: Master
def app(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return [b"Hello World"]
Hello World with wsgiref
$ python main.py127.0.0.1 - - [15/Apr/2016 10:24:21] "GET / HTTP/1.1" 200 11127.0.0.1 - - [15/Apr/2016 10:24:21] "GET /favicon.ico HTTP/1.1" 200 11
def app(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return [b"Hello World"]if __name__ == '__main__': from wsgiref.simple_server import make_server httpd = make_server('', 8080, app) httpd.serve_forever()
WAFで欲しい機能を考える
最低限欲しい機能• ルーティング
• どこにアクセスしても Hello World
• HTMLテンプレート
• 今はplain text返してるだけ
• Jinja2のTemplate Loaderを用意
最低限欲しい機能• 静的ファイルをいい感じに返す機能
• 本番だとNginxとか使うけど、開発中は...
• リクエスト・レスポンスオブジェクト
• リクエスト情報はenvが渡されてるけど、ただのdictなのでうまくパースしてほしい
• ステータスとかヘッダ情報をコントロール
a small and statically-typed web framework
kobinhttps://github.com/c-bata/kobin
a small and statically-typed web framework
kobinhttps://github.com/c-bata/kobin
Hello World
from kobin import Kobinapp = Kobin()
@app.route('^/(?P<name>\w*)$')def hello(name: str): return "Hello {}!!".format(name)
if __name__ == '__main__': app.run()
• 日本語: https://kobin.readthedocs.org/ja/latest/ • English: https://kobin.readthedocs.org/en/latest/
Hello World with Jinja2
import osfrom kobin import Kobin, template
app = Kobin()
@app.route('^/$')def index(): return template('index')
• https://github.com/c-bata/kobin-example • https://kobin.herokuapp.com/
特徴
• Type Hintsの活用
• Bottleのコードを読んでる時に結構混乱
• mypy 使いたい
• ルーティングへの活用
Routing in Django
from django.conf.urls import url
urlpatterns = [ url(r'^blog/page(?P<num>[0-9]+)/$', page),]
def page(request, num="1"): # Output the appropriate page of blog entries ...
https://docs.djangoproject.com/en/1.9/topics/http/urls/
• 引数が全て文字列
Routing in Bottle
from bottle import route
@route('/object/<id:int>')def callback(id): assert isinstance(id, int)
http://bottlepy.org/docs/dev/tutorial.html#request-routing
• 独自DSL
• 型が分かるため、view関数には型変換したオブジェクトを渡すことができる
ルーティングに対する考察
• 正規表現ベース (Django等)
• 自由度は高い
• 型情報を取得出来ない
• 独自DSL (Bottle, Flask等)
• 自由度は低い
• 型情報を自由に付けれる
Routing in Kobin
from kobin import Kobinapp = Kobin()
@app.route('^/years/(?P<year>\d{4})$')def casted_year( year: int ): return 'A "year" argument is integer? : {}’ \ .format(isinstance(year, int))
https://github.com/c-bata/kobin/blob/master/example/hello_world.py
• 正規表現により自由度が高い • Type Hintsの恩恵(IDE, mypy)をそのまま受けれる
Ecosystem Threats to Python
• Pythonのエコシステムはその巨大さゆえに、バージョンアップについていきづらい
• コミュニティとしてもPython3に移行していきたい
• Type Hintsを移行のきっかけに
PyCon APAC/Taiwan 2015: Keynote
References
• Documentations
• https://kobin.readthedocs.org/ja/latest/
• https://kobin.readthedocs.org/en/latest/
• Kobin Example
• https://github.com/c-bata/kobin-example
• https://kobin.herokuapp.com/
おまけ PEP333とPEP3333
PEP333 と PEP3333
$ python2.7>>> b'hoge' + u'日本語'u'hoge\u65e5\u672c\u8a9e'
$ python3.5>>> b'hoge' + u'日本語'Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: can't concat bytes to str
PEP333 と PEP3333
• PEP333 (WSGI v1.0)
• Python2ではbytesとstrを結合出来たり…
• Python3で文字列の扱いが大きく変わった
• PEP3333 (WSGI v1.0.1)
• 後方互換は保ったまま、文字列の扱いを整備して長年たまってたデファクトの修正案も取り込み
Thanks!