【发布时间】:2018-03-31 16:35:15
【问题描述】:
我目前正在重构我大约两年前编写的 Flask 应用程序,我怀疑我所做的一些事情不像使用该库那样优雅和干净。因此,我想就如何改善现状征求一些建议:
- 该应用提供了多个 API 端点,每个端点都可以通过
/<category>/<endpoint>形式的路由访问,其中<category>是 10 个不同类别之一。 - 对于每个
<category>,我创建了一个独特的Python模块<category>.py,将它放置在一个api/子目录和一个独特的flask.Blueprint(实际上是它的一个子类,见下文)并将其注册到主@ 987654327@. - 每个模块
<category>.py包含许多函数,它们充当各个类别的端点,并且每个都用路由装饰器进行装饰。
到目前为止一切顺利。
每个端点函数都接受许多参数,这些参数可以作为 GET 请求的参数传递,也可以作为 POST 请求的 JSON 有效负载中 parameter 字段的一部分传递。因此,在调用相应的端点函数之前,它会检查是否提供了正确数量的具有正确名称的参数。
此外,应用程序需要检查是否允许客户端调用某个函数。为此,读取由网络服务器设置的环境变量SSL_CLIENT_CERT(在我的例子中是通过 FCGI 的 lighttpd),并将其指纹与一些内部权限文件进行比较。
由于我不太清楚将上述逻辑放在哪里,我将flask.Blueprint 子类化并编写了我自己的(修改后的)route 装饰器(custom_route)。这个装饰器现在要么返回自定义错误响应(flask.Response 对象),要么返回自定义成功响应(从而使用从客户端传递的参数调用端点函数)。
所以模块category_xy.py 看起来像这样:
category_xy = CustomBlueprint('category_xy', __name__)
@category_xy.custom_route('/category_xy/some_endpoint',
auth_required=True,
methods=['GET', 'POST'])
def some_endpoint(foo, bar):
# do stuff
return '123'
CustomBlueprint 在单独的文件中定义为(部分伪代码):
from flask import Blueprint, Response, g, request
from functools import wraps
class CustomBlueprint(Blueprint):
def custom_route(self, rule, **options):
def decorator(f):
# don't pass the custom parameter 'auth_required' on to
# self.route
modified_options = dict(options)
if 'auth_required' in modified_options:
del modified_options['auth_required']
@self.route(rule, **modified_options)
@wraps(f)
def wrapper():
# do some authentication checks...
if not authenticiated():
return Response(...)
# check if correct paramters have been passed
if not correct_paramters():
return Response(...)
# extract parameter values from either GET or POST request
arg_values = get_arg_values(request)
# call the decorated function with these parameters
result = f(*arg_values)
return Response(result, ...)
return wrapper
return decorator
这行得通,但感觉一点也不干净,我认为应该有一种更好、更清洁的方法来做到这一点。将所有这些逻辑放在自定义装饰器中感觉非常错误。
有没有比 Flask 更有经验的人提供一些想法和/或最佳实践?
【问题讨论】:
-
我想你们的类别有一些共同点:相似的端点名称、授权机制、验证功能。对吗?
-
是的!每个端点函数都会触发服务器上的某些操作。一个类别中的所有操作都有些相关,并且通常也具有相似的端点名称。
标签: python http flask decorator python-2.x