2014-06-16 12 views
10

Mam aplikację kolbową z połączeniami oczekującymi ładunku JSON. Przed każda rozmowa jest przetwarzane, mam 2-stopniową błędzie proces sprawdzania:Flask: Dekorator do weryfikacji JSON i JSON Schema

  • twierdzą, że ładunek jest ważne JSON
  • twierdzą, że ładunek JSON jest zgodny z określonym schematem

Która jest realizowany w następujący sposób:

@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 

Ponieważ kod ten jest powielany przez wiele połączeń, zastanawiam się, czy mogę elegancko przenieść go do dekoratora, coś w formof:

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

Problemem jest to, że request argument jest niejawny: Mogę odnosić się do niego wewnątrz funkcji, ale nie jest to parametr do niego. Dlatego nie jestem pewien, jak go użyć w dekoratorze.

Jak mogę zaimplementować sprawdzanie poprawności za pomocą dekoratorów Python?

+0

Miałem nadzieję, że w tym celu znajdzie się biblioteka. Odpowiedź @ Martijna jest dość prosta, ale czy ktokolwiek o tym wie? –

Odpowiedz

24

Po prostu użyj kontekstu request globalnego w swoim dekoratorze. Jest dostępny pod numerem podczas każdego żądania.

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 

zastosować te dekoratorów przed stosującego @route dekorator; chcesz zarejestrować funkcję owijania, a nie oryginalną funkcję dla trasy:

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

Czy kolejność dekoratorów ma znaczenie? Czy dekorator '@ app.route' powinien być pierwszy? –

+1

@AdamMatan: '@route()' rejestruje żądanie wywołania, powinno być na wierzchu, aby zastosować je do funkcji zdobionego widoku. Dodam, że tak samo jak implementacje. –

+0

Czy nie powinno się "@ validate_json" iść na samo dno listy dekoratorów? –