noirbizarre / flask-restplus

Fully featured framework for fast, easy and documented API development with Flask
http://flask-restplus.readthedocs.org
Other
2.73k stars 506 forks source link

Attempting to @marshal_with fields.Wildcard(fields.List(fields.String())) #762

Open delewis13 opened 4 years ago

delewis13 commented 4 years ago

Attempting to return the following data structure to the user and document properly in swagger:

{ 'dynamic_key_1': ['string1', 'string2'], 'dynamic_key_2': ['string3]', ... }

i.e. a dictionary with dynamic keys, where values are a list of strings.

Using the example from here can get simple dynamic key data structure to work (see /test1), however, can't get it to work with lists (see /test2)

In particular, Swagger will render appropriately for /test2, however when I attempt to execute the request I hit an error (see stacktrace).

Based on this merge, seems like it should be doable, but can't figure out for the life of me! Help greatly appreciated!

Code

from flask import Flask
from flask_restplus import Api, Resource, fields

app = Flask(__name__)
api = Api(app)

# Render a dictionary with wildcard keys and strings for values
# WORKS
wild_1 = fields.Wildcard(fields.String)
wildcard_model_1 = api.model('wildcard model', {'*': wild_1})

@api.route('/test1')
class test1(Resource):
    @api.marshal_with(wildcard_model_1)
    def get(self):
        return {'John': 12, 'bob': 42, 'Jane': '68'}

# Render a dictionary wtih wildcard keys and lists of strings for values
# FAILS
wild_2 = fields.Wildcard(fields.List(fields.String))
wildcard_model_2 = api.model('wildcard model', {'*': wild_2})

@api.route('/test2')
class test2(Resource):
    @api.marshal_with(wildcard_model_2)
    def get(self):
        return {'John': ['field1'], 'bob': ['field2'], 'Jane': ['field3']}

if __name__ == '__main__':
    app.run(debug=True)

Error Messages/Stack Trace

Traceback (most recent call last):
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask/app.py", line 2463, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask/app.py", line 2449, in wsgi_app
    response = self.handle_exception(e)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask_restplus/api.py", line 584, in error_router
    return original_handler(e)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask/app.py", line 1866, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask/_compat.py", line 38, in reraise
    raise value.with_traceback(tb)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask/app.py", line 1951, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask_restplus/api.py", line 584, in error_router
    return original_handler(e)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask/app.py", line 1820, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask/_compat.py", line 38, in reraise
    raise value.with_traceback(tb)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask_restplus/api.py", line 325, in wrapper
    resp = resource(*args, **kwargs)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask/views.py", line 89, in view
    return self.dispatch_request(*args, **kwargs)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask_restplus/resource.py", line 44, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask_restplus/marshalling.py", line 256, in wrapper
    return marshal(resp, self.fields, self.envelope, self.skip_none, mask, self.ordered)
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask_restplus/marshalling.py", line 92, in marshal
    value == field.container.format(field.default):
  File "/Users/daniel.e.lewis/Documents/MyWizard/TG/aaam-ticketguru-flask/playground/flask-RestPlus/env/lib/python3.7/site-packages/flask_restplus/fields.py", line 287, in format
    for idx, val in enumerate(value)
TypeError: 'NoneType' object is not iterable

Environment

aniso8601==8.0.0 attrs==19.3.0 Click==7.0 Flask==1.1.1 flask-restplus==0.13.0 importlib-metadata==1.3.0 itsdangerous==1.1.0 Jinja2==2.10.3 jsonschema==3.2.0 MarkupSafe==1.1.1 more-itertools==8.0.2 pyrsistent==0.15.6 pytz==2019.3 six==1.13.0 Werkzeug==0.16.0 zipp==0.6.0

ziirish commented 4 years ago

Hello,

The patch has been merged indeed, but there was no new release so the current pip package does not include the fix yet.

I should also improve the doc regarding Nested/List fields with Wildcard.

You'll find some example in #737

jlongo-encora commented 4 years ago

When is going to be the next release?