tl;dr
Flask で簡単なアプリケーションを書く機会を頂いたので試行錯誤しながら書いていますが、特にエラーハンドラが心地よかったのでメモしておきます。
参考
- カスタムエラーページ — flask-docs-ja 0.10-dev documentation
- Python: Flask のエラーハンドラについて | CUBE SUGAR STORAGE
上記のサイトがとても参考になりました。感謝!
memo
エラーハンドラ
abort(xxx)
でエラーを返す際に任意のエラーを返すことが出来るとのことで、例えば Web アプリケーション内のエラー処理で abort(xxx)
と書いておけば、指定したエラー内容でクライアントに返却することが出来ます。
サンプル
以下のようなサンプルアプリケーションを書いてみました。
#!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flask from flask import abort, jsonify, request import json app = Flask(__name__) @app.route('/foo', methods=['POST']) def post_foo(): ''' Description - リクエストボディ {"id": "foo"} であれば ok を返す - リクエストボディ {"id": "foo"} であれば id is different を返す ''' if request.headers['Content-Type'] == 'application/json': id = request.json['id'] else: id = json.loads(request.form.to_dict().keys()[0])['id'] if id == 'foo': return jsonify({ 'message': 'ok'}) else: abort(404, { 'id': id }) @app.errorhandler(404) def error_handler(error): ''' Description - abort(404) した時にレスポンスをレンダリングするハンドラ ''' response = jsonify({ 'id': error.description['id'], 'message': 'id is different', 'result': error.code }) return response, error.code if __name__ == '__main__': app.run()
実行すると以下のような感じ。
$ curl -X POST -d '{"id": "foo"}' localhost:5000/foo 127.0.0.1 - - [01/Oct/2016 12:15:11] "POST /foo HTTP/1.1" 200 - { "message": "ok" } $ curl -X POST -d '{"id": "fo0"}' localhost:5000/foo 127.0.0.1 - - [01/Oct/2016 12:15:25] "POST /foo HTTP/1.1" 404 - { "id": "fo0", "message": "id is different", "result": 404 }
少し詳しく(1)
@app.errorhandler(404) def error_handler(error): ''' Description - abort(404) した時にレスポンスをレンダリングするハンドラ ''' response = jsonify({ 'id': error.description['id'], 'message': 'id is different', 'result': 404 }) return response, error.code
error_handler
の引数 error
にはどのようなメソッドが含まれているか確認してみます。
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__getitem__', '__getslice__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__unicode__', '__weakref__', 'args', 'code', 'description', 'get_body', 'get_description', 'get_headers', 'get_response', 'message', 'name', 'response', 'wrap']
それぞれのメソッドを見てみます。
(snip) @app.errorhandler(404) def error_handler(error): ''' Description - abort(404) した時にレスポンスをレンダリングするハンドラ ''' print dir(error) print 'error.args = ' + str(error.args) print 'error.code = ' + str(error.code) print 'error.description = ' + str(error.description) print 'error.message = ' + str(error.message) print 'error.name = ' + str(error.name) print 'error.response = ' + str(error.response) print 'error.wrap = ' + str(error.wrap) response = jsonify({ 'id': error.description['id'], 'message': 'id is different', 'result': error.code }) return response, error.code (snip)
以下のような結果となりました。
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__getitem__', '__getslice__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__unicode__', '__weakref__', 'args', 'code', 'description', 'get_body', 'get_description', 'get_headers', 'get_response', 'message', 'name', 'response', 'wrap'] error.args = () error.code = 404 error.description = {'id': u'fo0'} error.message = error.name = Not Found error.response = None error.wrap =>
abort(xxx)
を投げる時にエラーレスポンスに入れたい情報を引数として書いてあげれば error.description
で取り出して、エラーに合わせたメッセージをレンダリングしてクライアント返却することができるので嬉しいです。
少し詳しく(2)
以下のように書けば、それぞれのエラーでも一つの関数でハンドリングすることが出来ます。
@app.errorhandler(400) @app.errorhandler(404) @app.errorhandler(500) def error_handler(error): ''' Description - abort(400) / abort(404) / abort(500) した時にレスポンスをレンダリングするハンドラ ''' response = jsonify({ 'message': error.name, 'result': error.code }) return response, error.code
これも嬉しいです。
以上
メモでした。