web-dev-qa-db-ja.com

Flask:JSONおよびJSONスキーマを検証するためのデコレータ

flaskアプリケーションで、JSONペイロードを期待する呼び出しがあります。各呼び出しが処理される前に、2段階のエラーチェックプロセスがあります。

  • ペイロードが有効なJSONであることを表明します
  • JSONペイロードが特定のスキーマに準拠していることを表明します

これは次の方法で実装されます。

@app.route('/activate', methods=['POST'])
def activate():
    request_id = request.__hash__()

    # Assert that the payload is a valid JSON
    try:
        input = request.json
    except BadRequest, e:
        msg = "payload must be a valid json"
        return jsonify({"error": msg}), 400

    # JSON Schema Validation
    try:
        validate(request.json, app.config['activate_schema'])
    except ValidationError, e:
        return jsonify({"error": e.message}), 400

このコードは多くの呼び出しで複製されるので、次の形式のデコレータにエレガントに移動できるかどうか疑問に思います。

@validate_json
@validate_schema(schema=app.config['activate_schema'])
@app.route('/activate', methods=['POST'])
def activate():
    ....

問題は、request引数が暗黙的であるということです。関数内で参照できますが、パラメーターではありません。したがって、デコレータ内での使用方法がわかりません。

Pythonデコレータを使用して検証チェックを実装するにはどうすればよいですか?

18
Adam Matan

デコレータでグローバルなrequestコンテキストを使用するだけです。利用可能ですリクエスト中

from functools import wraps
from flask import (
    current_app,
    jsonify,
    request,
)


def validate_json(f):
    @wraps(f)
    def wrapper(*args, **kw):
        try:
            request.json
        except BadRequest, e:
            msg = "payload must be a valid json"
            return jsonify({"error": msg}), 400
        return f(*args, **kw)
    return wrapper


def validate_schema(schema_name):
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kw):
            try:
                validate(request.json, current_app.config[schema_name])
            except ValidationError, e:
                return jsonify({"error": e.message}), 400
            return f(*args, **kw)
        return wrapper
    return decorator

これらのデコレータを適用するbefore@routeデコレータを適用する;ルートの元の関数ではなく、ラップされた関数を登録する必要があります。

@app.route('/activate', methods=['POST'])
@validate_json
@validate_schema('activate_schema')
def activate():
    input = request.json
34
Martijn Pieters

遅い答えですが、おそらくマシュマロ(フラスコ-マシュマロ)やトーストしたマシュマロのようなものを探しています。

0
lostdorje