Flask restx MarshallingError 格式不正确
Flask restx MarshallingError incorrect formatting
问题背景
在使用 flask-restx 生成 api 文档时,我在使用 MarshallingError
时遇到了一些意外行为。我有一个自定义的 flask-restx 字段定义,如下所示。
class EnumField(StringMixin, Raw):
def __init__(self, enum_type, *args, **kwargs):
super().__init__(*args, **kwargs)
self.enum_type = enum_type
def format(self, value):
try:
return self.enum_type(value)
except ValueError as e:
raise MarshallingError(e)
def output(self, key, obj, **kwargs):
return self.format(obj[key]).value
其中 enum_type
很简单,例如
class DemoEnum(Enum):
a = 'a'
b = 'b'
c = 'c'
然后将其打包到 restx api.model
中,如下所示。
model = api.model('Demo', {"name": EnumField(enum_type=DemoEnum, required=True)})
问题
当我在 name
中输入一个整数时,正如预期的那样,我得到了一个很好的错误,如下所示。
{
"errors": {
"name": "1 is not of type 'string'"
},
"message": "Input payload validation failed"
}
然而,当我在我的枚举中输入一个 而不是 的值时(例如 "d"),错误似乎在我的 format
定义,但是,MarshallingError
并没有像预期的那样隐藏所有内部错误。这是输出内容的一小段。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>MarshallingError: 'string' is not a valid DemoEnum // Werkzeug Debugger</title>
...
问题
- 这是预期的行为吗?
- 是否有可能 return 更清晰的错误,如上所示?我的理解是我定义的
format
应该实现这个?
完整的测试申请
from flask_restx import Api, Resource
from flask_restx.fields import Raw, StringMixin, MarshallingError
from flask import Flask
from werkzeug.middleware.proxy_fix import ProxyFix
from enum import Enum
# =============================================================================
# Custom EnumField and Enum
# =============================================================================
class EnumField(StringMixin, Raw):
def __init__(self, enum_type, *args, **kwargs):
super().__init__(*args, **kwargs)
self.enum_type = enum_type
def format(self, value):
try:
return self.enum_type(value)
except ValueError as e:
raise MarshallingError(e)
def output(self, key, obj, **kwargs):
return self.format(obj[key]).value
class DemoEnum(Enum):
a = 'a'
b = 'b'
c = 'c'
# =============================================================================
# Demo restx model
# =============================================================================
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)
api = Api(app, version='1.0', title='Test API', validate=True)
ns = api.namespace('demo')
model = api.model('Demo', {
"name": EnumField(enum_type=DemoEnum, required=True)
})
# =============================================================================
# Api endpoint
# =============================================================================
@ns.route('/')
class Demo(Resource):
@ns.doc('create_demo')
@ns.expect(model, validate=True) # validate checks the input is provided
@ns.marshal_with(model, code=201)
def post(self):
'''Create demo'''
return api.payload
if __name__ == '__main__':
app.run(debug=True)
- 这是预期的行为吗?
是的,因为您的功能没有正确中止或 returning 任何东西。
- 是否有可能 return 更清晰的错误,如上所示?我的理解是我对格式的定义应该实现这个?
是的,您可以像以前一样修复错误,然后 return 您自己的消息并确保它使用 Flask 的 abort
正确中止
试试这个:
from flask import Flask, abort
def output(self, key, obj, **kwargs):
try:
return self.format(obj[key])
except (ValueError, MarshallingError) as e:
return abort(400, f'Unable to marshal field. errors: [{key}: {str(e)}]')
此示例的输出将是格式为 400 的错误:
{
"message": "Unable to marshal field. errors: [name: 'd' is not a valid DemoEnum]"
}
这不会影响来自 expect
装饰器的错误消息,即。如果您在名称字段中输入 1,您将收到与之前相同的消息。
问题背景
在使用 flask-restx 生成 api 文档时,我在使用 MarshallingError
时遇到了一些意外行为。我有一个自定义的 flask-restx 字段定义,如下所示。
class EnumField(StringMixin, Raw):
def __init__(self, enum_type, *args, **kwargs):
super().__init__(*args, **kwargs)
self.enum_type = enum_type
def format(self, value):
try:
return self.enum_type(value)
except ValueError as e:
raise MarshallingError(e)
def output(self, key, obj, **kwargs):
return self.format(obj[key]).value
其中 enum_type
很简单,例如
class DemoEnum(Enum):
a = 'a'
b = 'b'
c = 'c'
然后将其打包到 restx api.model
中,如下所示。
model = api.model('Demo', {"name": EnumField(enum_type=DemoEnum, required=True)})
问题
当我在 name
中输入一个整数时,正如预期的那样,我得到了一个很好的错误,如下所示。
{
"errors": {
"name": "1 is not of type 'string'"
},
"message": "Input payload validation failed"
}
然而,当我在我的枚举中输入一个 而不是 的值时(例如 "d"),错误似乎在我的 format
定义,但是,MarshallingError
并没有像预期的那样隐藏所有内部错误。这是输出内容的一小段。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>MarshallingError: 'string' is not a valid DemoEnum // Werkzeug Debugger</title>
...
问题
- 这是预期的行为吗?
- 是否有可能 return 更清晰的错误,如上所示?我的理解是我定义的
format
应该实现这个?
完整的测试申请
from flask_restx import Api, Resource
from flask_restx.fields import Raw, StringMixin, MarshallingError
from flask import Flask
from werkzeug.middleware.proxy_fix import ProxyFix
from enum import Enum
# =============================================================================
# Custom EnumField and Enum
# =============================================================================
class EnumField(StringMixin, Raw):
def __init__(self, enum_type, *args, **kwargs):
super().__init__(*args, **kwargs)
self.enum_type = enum_type
def format(self, value):
try:
return self.enum_type(value)
except ValueError as e:
raise MarshallingError(e)
def output(self, key, obj, **kwargs):
return self.format(obj[key]).value
class DemoEnum(Enum):
a = 'a'
b = 'b'
c = 'c'
# =============================================================================
# Demo restx model
# =============================================================================
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)
api = Api(app, version='1.0', title='Test API', validate=True)
ns = api.namespace('demo')
model = api.model('Demo', {
"name": EnumField(enum_type=DemoEnum, required=True)
})
# =============================================================================
# Api endpoint
# =============================================================================
@ns.route('/')
class Demo(Resource):
@ns.doc('create_demo')
@ns.expect(model, validate=True) # validate checks the input is provided
@ns.marshal_with(model, code=201)
def post(self):
'''Create demo'''
return api.payload
if __name__ == '__main__':
app.run(debug=True)
- 这是预期的行为吗?
是的,因为您的功能没有正确中止或 returning 任何东西。
- 是否有可能 return 更清晰的错误,如上所示?我的理解是我对格式的定义应该实现这个?
是的,您可以像以前一样修复错误,然后 return 您自己的消息并确保它使用 Flask 的 abort
试试这个:
from flask import Flask, abort
def output(self, key, obj, **kwargs):
try:
return self.format(obj[key])
except (ValueError, MarshallingError) as e:
return abort(400, f'Unable to marshal field. errors: [{key}: {str(e)}]')
此示例的输出将是格式为 400 的错误:
{
"message": "Unable to marshal field. errors: [name: 'd' is not a valid DemoEnum]"
}
这不会影响来自 expect
装饰器的错误消息,即。如果您在名称字段中输入 1,您将收到与之前相同的消息。