【问题标题】:what is error handling best practice in Flask restAPI什么是 Flask REST API 中的错误处理最佳实践
【发布时间】:2021-07-25 15:00:19
【问题描述】:

烧瓶==1.1.2 Python==3.8

我正在构建一个服务于机器学习模型的 restAPI。将向我的 restAPI 发送请求并使用结果将其发送给用户的同事希望我向他发送适当的错误消息以及 status_code。

我已经对如何正确处理 Python Flask 中的错误进行了大量搜索,但我仍然坚持对于可扩展和可维护的 restAPI 的最佳实践。

目前,每当发生错误时,我只需返回带有消息和状态代码的字典。我想缓解这种方法的一些问题:

  1. 如果函数内部发生错误,它必须将包含错误消息的字典返回到调用函数的位置,并需要检查它是否真的是错误,如果是则返回错误消息

    例子:

     def add_data(x,y):
         """return addition of x,y. They both need to be integers"""
         if type(x) != int:
             return "x has wrong datatype"
         if type(y) != int:
             return "y has wrong datatype"
         return x+y
    
     @app.route("/predict", methods=["POST"])
     def predict():
         data = request.get_json()
         result = add_data(data["x"], data["y"])
         if type(result) == str:
             return {"message":"input error", "status":222}
    
  2. 不能在函数内破坏代码。

    根据一些参考资料

    我已将代码更改为以下内容:

     class InputError(Exception):
         status_code = 400
         def __init__(self, message, status_code=None):
             Exception.__init__(self)
             self.message = message
             if status_code is not None:
                 self.status_code = status_code
    
         def __str__(self):
             return repr(self.status_code)
    
    
     def add_data(x,y):
         if type(x) != int:
             raise InputError("x has wrong datatype", status_code=222)
         if type(y) != int:
             raise InputError("y has wrong datatype", status_code=222)
         return x+y
    

    这确实破坏了发现错误的代码,但是我无法像以前一样找出如何返回字典。

我该怎么做?哪种做法被认为是最佳做法?

【问题讨论】:

  • 您将业务和传输逻辑组合在一起。 add_data 不应该决定代表结果的适当 HTTP 状态代码是什么(当然也不应该决定它是 222,一个在 success 类中没有定义含义的代码) . add_data 应该只是抛出一个TypeError,然后predict 可以抓住它并做出适当的回应。您还应该使用isinstance 进行类型比较。
  • 如果我使用没有定义含义的状态码,如 1、2、3、4、5 等...?所以如果我不想将业务和传输逻辑一起破坏,我不应该输出状态码?
  • 你的意思是有你自己的内部状态码,传输层转换成HTTP状态码?我想这没关系,您可以使用枚举来表示它们,因此它们是名称而不是幻数:docs.python.org/3/library/enum.html。但是,这与抛出您自己的业务相关错误有什么不同呢?

标签: python rest flask


【解决方案1】:

解决方案是使用错误处理程序 https://flask.palletsprojects.com/en/1.1.x/errorhandling/

在你的情况下:

@app.errorhandler(InputError)
def handle_input_error(e):
    return {"message": e["message"], "status": e["status"]}

现在每当你在代码中的某处引发 InputError 时,flask 都会知道调用这个方法并返回这个响应

如果您有更多类型的错误,我会切换到更一般的错误

class MyErrors(Exception):
    status_code: int
    
    def __init__(self, message):
        super(MyErrors, self).__init__(message)
        self.message = message
        
    def response(self):
        return {"message": self.message, "status": self.status_code}
    
class InputError(MyErrors):
    status_code = 222
    
class SomeOtherError(MyErrors):
    status_code = 123

@app.errorhandler(MyErrors)
def handle_errors(e):
    return e.response()

【讨论】:

  • 我还是不会把状态码放在业务错误里;把它放在错误处理程序本身,它属于传输域。
  • 关于如何构建它们的任何指南?你写的脚本应该在 app.py 里面?
  • @haneulkim 我会将所有异常都放在一个单独的文件中,错误处理程序也会放在它自己的文件中,以防您将来添加更多内容
猜你喜欢
  • 2016-12-26
  • 2020-12-24
  • 1970-01-01
  • 2011-09-22
  • 2020-06-05
  • 1970-01-01
  • 1970-01-01
  • 2019-10-03
  • 1970-01-01
相关资源
最近更新 更多