我使用Flask-RESTful来创建API端点,我用这种方式指定URL:
api.add_resource(ListVersionsByStaff, '/shots/versions/<int:project_id>/<int:staff_id>')
api.add_resource(ListSeasons, '/seasons/<int:project_id>')
如果给定的参数不是int
,Flask-RESTful将返回错误响应,但它将返回HTML响应。
如何返回自定义JSON错误响应,例如:
except InvalidParameter as err:
abort(err.status_code, **err.to_dict())
以这种方式检查值也不起作用,参数始终为String
class SpecificProject(Resource):
def get(self, project_id):
print("DEBUG: project_id is [", project_id, "]", file=sys.stderr)
print("DEBUG: Type is [", type(project_id), "]", file=sys.stderr)
if isinstance(project_id, int):
pass
else:
message = "'{}' is not a valid project_id. Hint: this is a number representing primary key.".format(project_id)
errors = {}
errors['resource'] = "Project"
errors['field'] = "project_id"
errors['code'] = "invalid"
errors['stack_trace'] = ""
abort(400, message=message, errors=errors)
输出:
DEBUG: project_id is [ 1 ]
DEBUG: Type is [ <class 'str'> ]
答案 0 :(得分:0)
我的解决方案是扩展Flask-RESTful Api
类并实现我的自定义错误处理程序。 official documentation explains a little bit about extending,但没有详细说明。
我的应用程序中的所有错误都在此结构中
class InvalidParameter(Exception):
status_code = 400
def __init__(self, message, status_code=None, resource=None,
field=None, code=None, stack_trace=None):
Exception.__init__(self)
self.message = message
if status_code is not None:
self.status_code = status_code
self.resource = resource
self.field = field
self.code = code
self.stack_trace = stack_trace
def to_dict(self):
rv = {}
errors = {}
rv['message'] = self.message
errors['resource'] = self.resource
errors['field'] = self.field
errors['code'] = self.code
errors['stack_trace'] = self.stack_trace
rv['errors'] = errors
return rv
这就是Flask-RESTful默认返回的内容
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
输出应为JSON,格式为
{
"message": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. You have requested this URI [/projects/1asd] but did you mean /projects/<int:project_id> or /projects or /project/new ?",
"errors": {
"resource": null,
"field": null,
"code": "invalid_url",
"stack_trace": null
}
}
扩展Api
课程并覆盖handle_error
错误的404
方法
class CustomApi(Api):
def handle_error(self, e):
code = getattr(e, 'code', 404)
if code == 404:
response_dict = Api.handle_error(self, e).__dict__
resp_message = response_dict['response'][0]
error_message = re.sub(r'.*"(.*)".*', r'\1', resp_message.decode('utf-8'), flags=re.DOTALL)
err = InvalidParameter(error_message, stack_trace=None,
resource=None, code="invalid_url", field=None)
return self.make_response(err.to_dict(), 404) #{'message': "something", 'error': {'sub1': 'val1'}}, 404)
return super(Api, self).handle_error(e)
handle_error
字典采用此格式
{'headers': Headers([('Content-Type', 'application/json'), ('Content-Length', '263')]), '_status_code': 404, '_status': '404 NOT FOUND', 'direct_passthrough': False, '_on_close': [], 'response': [b'{\n "message": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. You have requested this URI [/projects/1asd] but did you mean /projects/<int:project_id> or /projects or /project/new ?"\n}\n']}
我想重新使用生成的'response':'message'
,但不是默认格式。 message
没有正确的JSON格式,因此我使用此正则表达式删除除message
内容之外的所有内容
error_message = re.sub(r'.*"(.*)".*', r'\1', resp_message.decode('utf-8'), flags=re.DOTALL)
请注意,需要re.DOTALL
来删除Flask-RESTful添加的\n
。
实际构建JSON响应的代码是self.make_response(err.to_dict(), 404)
对于所有其他非404错误(例如400,500,203),错误只会传递给原始的Flask-RESTful Api类。
请注意,在创建Flask应用程序时,您需要使用自定义Api类,并捕获所有404错误:
app = Flask(__name__)
api = CustomApi(app, catch_all_404s=True)