RESTful api design: handle exceptions through nested functions (python, flask)
我想改进我的编码风格,在设计API时更好地掌握
我有嵌套函数,当一个函数捕获到一个执行时,我将把异常传递给另一个函数,依此类推。
但是像这样,我可以对同一个错误进行多次检查。我指的是:[在python中使用try与if考虑试运行成本。
如何在嵌套函数中只处理一次错误?
例如。
- 我有一个函数
f(key) 对键执行一些操作;结果是传递给其他函数g() 、h() 。 - 如果结果符合需要数据结构,g()。h()将操作并返回更新结果
- 装饰器将返回最终结果或返回所遇到的第一个错误,指出提出方法(
f() 、g() 或h() )。
我正在做这样的事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def f(key): try: #do something return {'data' : 'data_structure'} except: return {'error': 'there is an error'} @application.route('/') def api_f(key): data = f(k) try: # do something on data return jsonify(data) except: return jsonify({'error':'error in key'}) |
imo
在你的例子中,最好把
引发另一个错误(请小心,因为这将重置堆栈跟踪):
1 2 3 4 | try: ### Do some stuff except: raise CustomError('Bad things') |
执行一些错误处理(例如日志记录、清理等):
1 2 3 4 5 6 7 8 | try: ### Do some stuff except: logger.exception('Bad things') cleanup() ### Re-raise the same error raise |
否则,就让错误冒泡。
后续功能(如
1 2 3 4 5 6 7 8 | def handle_json(data): try: return json.dumps(data) except TypeError, e: logger.exception('Could not decode json from %s: %s', data, e) # Could also re-raise the same error raise CustomJSONError('Bad things') |
然后,您将在堆栈的更上一层拥有处理程序来处理原始错误或自定义错误,最后是一个可以处理任何错误的全局处理程序。在我的flask应用程序中,我创建了自定义的错误类,我的全局处理程序能够解析这些类并用它们做一些事情。当然,全局处理程序也被配置为处理意外错误。
例如,我可能有一个用于所有HTTP错误的基类…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ### Not to be raised directly; raise sub-class instances instead class BaseHTTPError(Exception): def __init__(self, message=None, payload=None): Exception.__init__(self) if message is not None: self.message = message else: self.message = self.default_message self.payload = payload def to_dict(self): """ Call this in the the error handler to serialize the error for the json-encoded http response body. """ payload = dict(self.payload or ()) payload['message'] = self.message payload['code'] = self.code return payload |
…针对各种HTTP错误进行扩展:
1 2 3 4 5 6 7 8 9 10 11 12 13 | class NotFoundError(BaseHTTPError): code = 404 default_message = 'Resource not found' class BadRequestError(BaseHTTPError): code = 400 default_message = 'Bad Request' class NotFoundError(BaseHTTPError): code = 500 default_message = 'Internal Server Error' ### Whatever other http errors you want |
我的全局处理程序看起来是这样的(我使用的是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class RestAPI(flask_restful.Api): def handle_error(self, e): code = getattr(e, 'code', 500) message = getattr(e, 'message', 'Internal Server Error') to_dict = getattr(e, 'to_dict', None) if code == 500: logger.exception(e) if to_dict: data = to_dict() else: data = {'code': code, 'message': message} return self.make_response(data, code) |
使用
同样,在应用程序的其他地方,也有理由将错误转换为一些有用的返回值,但对于上述情况,