简体   繁体   English

Flask restx MarshallingError 格式不正确

[英]Flask restx MarshallingError incorrect formatting

Problem context问题上下文

I'm experiencing some unexpected behaviour with MarshallingError , when generating api documentation using flask-restx.在使用 flask-restx 生成 api 文档时,我遇到了MarshallingError的一些意外行为。 I have a custom flask-restx field definition, like below.我有一个自定义的 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

where enum_type is something simple like其中enum_type很简单,例如

class DemoEnum(Enum):
    a = 'a'
    b = 'b'
    c = 'c'

This is then packaged inside a restx api.model , which looks like the following.然后将其打包在一个 restx api.model中,如下所示。

model = api.model('Demo', {"name": EnumField(enum_type=DemoEnum, required=True)})

Issue问题

When I enter an integer into name , as expected, I'm getting a nice error like below.当我在name中输入 integer 时,正如预期的那样,我得到了一个很好的错误,如下所示。

{
  "errors": {
    "name": "1 is not of type 'string'"
  },
  "message": "Input payload validation failed"
}

However, when I then enter a value that is not in my enum ("d" for instance), the error seems to be caught in my format definition, however, MarshallingError isn't hiding all of the internal errors as expected.但是,当我输入一个不在我的枚举中的值(例如“d”)时,我的format定义中似乎捕获了错误,但是, MarshallingError并没有像预期的那样隐藏所有内部错误。 Here's a short snippet of what is being output.这是 output 的简短片段。

<!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>
...

Quesions问题

  1. Is this expected behaviour?这是预期的行为吗?
  2. Is it possible to return a cleaner error, like the one shown above?是否可以返回更清晰的错误,如上图所示? My understanding was that my definition of format should achieve this?我的理解是我对format的定义应该实现这一点?

Full application for testing完整的测试申请

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)
  1. Is this expected behaviour?这是预期的行为吗?

Yes, because you're function is not aborting correctly or returning anything.是的,因为您是 function 没有正确中止或返回任何内容。

  1. Is it possible to return a cleaner error, like the one shown above?是否可以返回更清晰的错误,如上图所示? My understanding was that my definition of format should achieve this?我的理解是我对格式的定义应该实现这一点?

Yes, you can rescue the error like you were doing, then return your own message and make sure it aborts properly using Flask's abort是的,您可以像以前一样挽救错误,然后返回您自己的消息并确保它使用 Flask 的中止正确abort

Try this:尝试这个:

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)}]')

The output for this example would be a 400 error formatted:此示例的 output 将是 400 错误格式:

{
  "message": "Unable to marshal field. errors: [name: 'd' is not a valid DemoEnum]"
}

This will not effect the error messaging from the expect decorator, ie.这不会影响来自expect装饰器的错误消息,即。 if you enter 1 for the name field you will receive the same message as before.如果您在名称字段中输入 1,您将收到与以前相同的消息。

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

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