Bottleについての覚書
MEMO-1. ルーティング設定を一箇所にまとめる
- 通常のルーティング設定は↓のようにデコレータでルーティングを設定する
from bottle import route, abort
@route('/', method='GET')
def index():
return "Hello Bottle."
- とはいえ、複数のコントローラがあると個々の関数にルーティング設定が紐付けられると管理が面倒である
- Laravelのようにルーティングとコールバックをまとめて指定したくなる
// Laravelのルーティング設定
Route::get('/user', [UserController::class, 'index']);
import bottle
from . import controller
app = bottle.Bottle()
app.route('/', 'GET', controller.index)
- これでルーティングが増えても一箇所で集中管理することができる
MEMO-2. エラーを返却する
-
abort
で任意のステータスコードを返却すればOK
from bottle import route, abort
@route('/', method='GET')
def index():
abort(401)
MEMO-3. JSONのレスポンスを返却する
-
response.content_type
をapplication/json
に設定した上でDictを返却すればOK
from bottle import route, abort
@route('/', method='GET')
def index():
response.content_type = 'application/json'
return {'status': 'OK'}
MEMO-4. ファイルのアップロード
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
</form>
# アップロードされるファイルが1つの場合
@route('/upload', method='POST')
def upload():
upload_file = request.files.get('<INPUTタグのNAME属性>') # この例では'file'
save_path = os.path.join('<ファイル保存パス>', upload_file.filename)
upload_file.save(save_path)
return redirect('/')
MEMO-5. ファイルアップロード時にRequest Entity Too Largeが発生する際の対処法
- リクエスト時に受け付ける最大データ長はデフォルトでは100KB程度なので、少し大きめのファイルをアップロードするとエラーが起きる
-
MEMFILE_MAX
のサイズを上げることでリクエストの最大長を変更することができる
# coding: utf-8
import bottle
app = bottle.Bottle()
# リクエストの最大長を10MBに設定
app.MEMFILE_MAX = 1024 * 1000 * 10
@app.route('/upload', method='POST')
def upload():
upload_file = request.files.get('<INPUTタグのNAME属性>') # この例では'file'
save_path = os.path.join('<ファイル保存パス>', upload_file.filename)
upload_file.save(save_path)
return redirect('/')
MEMO-6. ファイルのダウンロード
MEMO-7. gunicornで起動
-
web.py
というファイルに処理が記述されていると仮定
-
web.py
の内容は↓の通り
# coding: utf-8
import bottle
app = bottle.Bottle()
@app.route('/', method='GET')
def index():
response.content_type = 'application/json'
return {'status': 'OK'}
-
gunicorn
のパラメータを↓のようにするとgunicorn
で起動する(ワーカー数やポート番号は適宜変更する)
gunicorn -w 1 --bind 0.0.0.0:8080 web:app
MEMO-8. プラグイン
プラグイン基礎知識
- 他のフレームワークではミドルウェアとか呼ばれるもの
- ↓は公式ドキュメントにある簡単なプラグインのサンプル
- 引数の
callback
はルーティング設定で登録したコールバック関数で、その実行の前後に処理を挟むことができる
-
body = callback(*args, **kwargs)
の前に処理を書けば事前処理となり、後ろに処理を書けば事後処理となる
from bottle import response, install
import time
def stopwatch(callback):
def wrapper(*args, **kwargs):
start = time.time()
body = callback(*args, **kwargs) # <= コールバック関数を実行
end = time.time()
response.headers['X-Exec-Time'] = str(end - start) # <= レスポンスヘッダーに情報を追加している
return body
return wrapper
install(stopwatch)
- 最小限かつ何も処理を行わないプラグインは↓のようになり、これをベースにプラグインを自作すればよいということになる
from bottle import response, install
def my_plugin(callback):
def wrapper(*args, **kwargs):
return callback(*args, **kwargs)
return wrapper
install(my_plugin)
プラグインAPI
# クラス名は任意
class MyPlugin:
name = 'myplugin' # <= プラグインの登録名
api = 2 # <= プラグインバージョン(現状は2が最新)
# プラグインの初期化処理
def __init__(self):
pass
# プラグイン登録時に実行される処理
def setup(self, app):
pass
# プラグインのメイン処理
def apply(self, callback, route):
def wrapper(*args, **kwargs):
return callback(*args, **kwargs)
return wrapper
from bottle import response, install
import MyPlugin
install(MyPlugin())
どのような用途でプラグインを使うか?
- セッション管理(セッションID発行、Cookie発行など)
- CSRFトークン認証(トークンの発行、認証)
- ロギング
- などアプリケーションで共通して行われる処理
参考資料