2015-05-27 12 views
5

My Bottle Apps nicht sehr trocken, hier ist ein Testfall:DRY Validierung in der Flasche?

from uuid import uuid4 
from bottle import Bottle, response 

foo_app = Bottle() 

@foo_app.post('/foo') 
def create(): 
    if not request.json: 
     response.status = 400 
     return {'error': 'ValidationError', 'error_message': 'Body required'} 
    body = request.json 
    body.update({'id': uuid4().get_hex()) 
    # persist to db 
    # ORM might set 'id' on the Model layer rather than setting it here 
    # ORM will validate, as will db, so wrap this in a try/catch 
    response.status = 201 
    return body 

@foo_app.put('/foo/<id>') 
def update(id): 
    if not request.json: 
     response.status = 400 
     return {'error': 'ValidationError', 'error_message': 'Body required'} 
    elif 'id' not in request.json: 
     response.status = 400 
     return {'error': 'ValidationError', 'error_message': '`id` required'} 
    db = {} # should be actual db cursor or whatever 
    if 'id' not in db: 
     response.status = 404 
     return {'error': 'Not Found', 
       'error_message': 'Foo `id` "{id}" not found'.format(id)} 
    body = request.json 
    # persist to db, return updated object 
    # another try/catch here in case of update error (from ORM and/or db) 
    return body 

Eine Möglichkeit, dieses Problem zu lösen, ist eine globale Fehlerbehandlung haben, und alle über den Ort Fehler zu erhöhen.

Eine andere ist Dekoratoren, die auch Overhead-Probleme haben.

Gibt es eine bessere Möglichkeit, die Validierung jeder Route durchzuführen? - Ich denke an so etwas wie:

foo_app.post('/foo', middleware=[HAS_BODY_F, ID_IN_DB_F]) 
+0

Nur neugierig (da ich sie alle über den Platz benutzen) - Sie haben keine Referenzen für‚Dekorateure ... haben Kopf Fragen‘? –

+0

Ich erinnere mich nicht genau, als ich davon hörte, aber hier ist ein Blog-Post darüber: http://blog.dscpl.com.au/2014/02/performance-overhead-when-applying.html –

+0

Danke, zu schätzen Referenz. –

Antwort

2

Ended up Bottle integrierte "Middleware" genannt „Plugins zu finden, "(reference):

from bottle import Bottle, request, response 

app = Bottle() 


def has_body(f): 
    def inner(*args, **kwargs): 
     if request.json: 
      return f(*args, **kwargs) 

     response.status = 400 
     return {'error': 'ValidationError', 
       'error_message': 'Body is required (and must be JSON).'} 
    return inner 


def body_req(required): 
    def body_req_middleware(f): 
     def inner(*args, **kwargs): 
      intersection = required.intersection(set(request.json.keys())) 
      if intersection != required: 
       response.status = 400 
       return {'error': 'ValidationError', 
         'error_message': 'Key(s): {} are not in JSON payload' 
         ''.format(', '.join('{!r}'.format(k) 
              for k in required - intersection))} 
      return f(*args, **kwargs) 
     return inner 
    return body_req_middleware 


@app.post('/foo', apply=(has_body, body_req({'id', 'f'}))) 
def get_foo(): 
    return {'foo': 'bar'} 
0

Hier ist meine Lösung ist die Validierung trocken, endete mit einem Dekorateur up:

from itertools import imap, ifilter  
from bottle import Bottle, request, response 

app = Bottle() 

middleware = lambda functions: lambda caller: lambda *args, **kwargs: next(
    ifilter(None, imap(lambda g: g(*args, **kwargs), functions)), 
    caller(*args, **kwargs) 
) 


def has_body(*args, **kwargs): 
    if not request.json: 
     response.status = 400 
     return {'error': 'ValidationError', 
       'error_message': 'Body is required (and must be JSON).'} 


def body_req(required): 
    def inner(*args, **kwargs): 
     intersection = required.intersection(set(request.json.keys())) 
     if intersection != required: 
      response.status = 400 
      return {'error': 'ValidationError', 
        'error_message': 'Key(s): {} are not in JSON payload'.format(
        ', '.join(imap(lambda key: "'{key}'".format(key=key), 
           required - intersection)))} 

    return inner 


@app.post('/foo') 
@middleware([has_body, body_req({'id', 'f'})]) 
def get_foo(): 
    return {'foo': 'bar'}