background
When using flask+flask-restplus, the interface function returns an object that can be serialized by json when the business is normal
@ns.route('/hello')
class Hello(Resource):
def get(self):
return ['hello', 'hi']
The interface returns the following content:
[
"hello",
"hi"
]
When a business exception (such as a parameter error detected), the abort function will usually be called and it will throw an HTTPException
@ns.route('/error')
class Error(Resource):
def get(self):
abort(400, 'params error')
The interface returns the following content:
{
"message": "params error"
}
Due to company specification requirements, a unified http request response template is required, as follows:
{
'code': 100000,
'message': 'xxx'
'data': 'hello'
}
Therefore, we need to modify the interface return format.
Unified processing of interface return value
In order not to change the original encoding habits and to meet the above requirements for return formats, we can use the representation decorator of flask-restplus to register an interface return content processor
@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
Now let’s request the above two interfaces, and the return format becomes the format we want
{"code": 100000, "data": ["hello", "hi"]}
{"code": 200000, "message": "params error"}
Custom exception handling
If an exception that is not an HTTPException is thrown, you will find that the specific exception content cannot be obtained, and you will only get the following results:
{"code": 200000, "message": "Internal Server Error"}
If you want to return some specified exception content, for example, we have customized the following exception class:
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 = 'Insufficient permissions'
Then we can use the errorhandler decorator of flask-restplus to register an exception handler, in which we convert the custom exception to the normal interface return format
@api.errorhandler(BaseException)
def handle_base_exception(error):
return error.to_dict(), error.http_code
This way, custom exceptions can also return exception content
{"code": 200001, "message": "Insufficient permissions"}
Of course, we cannot turn all exceptions into BaseException and throw them all in one go. If we do this, we will also throw exceptions caused by unsolicitation of the program, which will bring bad experience to the user.