繁体   English   中英

使用Flask-RESTful的JSON响应进行自定义参数验证

[英]Custom parameter validation with JSON response for Flask-RESTful

我正在使用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'> ]

我的解决方案是扩展Flask-RESTful Api类并实现我的自定义错误处理程序。 官方文档对扩展进行了一些解释 ,但没有提供足够的细节。

自定义错误消息

我的应用程序中的所有错误都在此结构中

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.DOTALLre.DOTALL Flask-RESTful添加的\\n

实际构建JSON响应的代码是self.make_response(err.to_dict(), 404)

对于所有其他非404错误(例如400、500、503),该错误仅传递给原始的Flask-RESTful Api类。

请注意,在创建Flask应用程序时,您需要使用自定义的Api类,并捕获所有404错误:

app = Flask(__name__) 
api = CustomApi(app, catch_all_404s=True)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM