在flask-restplus下统一接口返回格式

背景

在使用flask+flask-restplus时,业务正常时接口函数返回一个可以json序列化的对象

@ns.route(/hello)
class Hello(Resource):
    def get(self):
        return [hello, hi]

接口返回内容如下:

[
    "hello",
    "hi"
]

当业务异常(比如检测到参数错误)时,一般调用abort函数,它会抛出一个HTTPException

@ns.route(/error)
class Error(Resource):
    def get(self):
        abort(400, params error)

接口返回内容如下:

{
          
   
    "message": "params error"
}

由于公司规范要求,需要使用统一的http请求响应模板,如下:

{
          
   
    code: 100000,
    message: xxx
    data: hello
}

因此,我们需要对接口返回格式进行改造。

接口返回值统一处理

为了不改变原有的编码习惯,又能够达到以上返回格式的要求,我们可以使用flask-restplus的representation装饰器来注册一个接口返回内容处理器

@api.representation(application/json)
def output_json(data, code, headers=None):
    result = {
          
   }
    if api.specs_url == request.url:
        result = data
    elif code in (200, 201, 204):
        result[code] = 100000
        result[data] = data
    else:
        result[code] = data.get(code) or 200000
        result[message] = data[message]
    response = make_response(json.dumps(result), code)
    response.headers.extend(headers or {
          
   })
    return response

现在再来请求上面的两个接口,返回格式变成了我们想要的格式

{
          
   "code": 100000, "data": ["hello", "hi"]}
{
          
   "code": 200000, "message": "params error"}

自定义异常处理

如果抛出不是HTTPException的异常,会发现并不能得到具体的异常内容,只会得到以下结果:

{
          
   "code": 200000, "message": "Internal Server Error"}

如果想要将一些指定的异常内容返回,比如我们自定义了以下的异常类:

class BaseException(Exception):
    http_code = 500
    business_code = 200000

    def __init__(self, message=None):
        if message:
            self.message = message

    def to_dict(self):
        data = {
          
   code: self.business_code, message: self.message}
        return data


class InsufficientPrivilege(BaseException):
    http_code = 403
    business_code = 200001
    message = 权限不足

那么我们可以使用flask-restplus的errorhandler装饰器来注册一个异常处理器,在这个处理器中将自定义异常转换为正常接口返回格式

@api.errorhandler(BaseException)
def handle_base_exception(error):
    return error.to_dict(), error.http_code

这样自定义异常也可以返回异常内容了

{
          
   "code": 200001, "message": "权限不足"}

当然我们也不能将异常都转为BaseException一股脑抛出,这样做的话会将因程序不健壮导致的异常也抛出,会给用户带来不好的体验。

经验分享 程序员 微信小程序 职场和发展