Python 瓶内干法验证?
我的瓶子应用程序不是很干,下面是一个测试案例:Python 瓶内干法验证?,python,validation,bottle,middleware,python-decorators,Python,Validation,Bottle,Middleware,Python Decorators,我的瓶子应用程序不是很干,下面是一个测试案例: 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_mess
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
这是我的干式验证解决方案,最终由一个装饰师完成:
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'}
最终找到了瓶子的内置“中间件”,称为“插件”():
我只是好奇(因为我到处都在使用它们)-你有关于“装饰者…有开销问题”的参考资料吗?我不记得我什么时候听说过这个,但这里有一篇关于它的博客文章:谢谢,感谢你的参考。FWIW,共识是(比我更伟大的Pythonistas)装饰者天生不会增加太多开销,所以我想我建议重新考虑这个方法。好吧,我想我可以添加一个装饰器(它需要一个函数列表)。请参阅我的答案,并根据您认为合适的方式进行评论/投票。谢谢
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'}
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'}