Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

automatic swagger documentation fails when multiple locations provided to regparser #476

Open
db0 opened this issue Sep 22, 2022 · 3 comments
Labels
bug Something isn't working

Comments

@db0
Copy link

db0 commented Sep 22, 2022

Code

class AsyncGenerate(Resource):
    parser = reqparse.RequestParser()
    parser.add_argument("prompt", type=str, required=True, help="The prompt to generate from")
    parser.add_argument("api_key", type=str, required=True, help="The API Key corresponding to a registered user", location=['headers', 'json'])
    parser.add_argument("params", type=dict, required=False, default={}, help="Extra generate params to send to the SD server")
    parser.add_argument("servers", type=str, action='append', required=False, default=[], help="If specified, only the server with this ID will be able to generate this prompt")
    @api.expect(parser)
    def post(self, api_version = None):

Expected Behavior

The swagger API should renger my regparser requirements correctly

Actual Behavior

If I set the location parameter of add_argument to a list of locations, the api.expect(parser) errors

Error Messages/Stack Trace

2022-09-22 16:44:58,743 - ERROR - api:576 - Unable to render schema
Traceback (most recent call last):
  File "C:\Users\Db0\AppData\Roaming\Python\Python310\site-packages\flask_restx\api.py", line 571, in __schema__
    self._schema = Swagger(self).as_dict()
  File "C:\Users\Db0\AppData\Roaming\Python\Python310\site-packages\flask_restx\swagger.py", line 239, in as_dict
    serialized = self.serialize_resource(
  File "C:\Users\Db0\AppData\Roaming\Python\Python310\site-packages\flask_restx\swagger.py", line 438, in serialize_resource
    doc = self.extract_resource_doc(resource, url, route_doc=route_doc)
  File "C:\Users\Db0\AppData\Roaming\Python\Python310\site-packages\flask_restx\swagger.py", line 343, in extract_resource_doc
    method_params = self.expected_params(method_doc)
  File "C:\Users\Db0\AppData\Roaming\Python\Python310\site-packages\flask_restx\swagger.py", line 382, in expected_params
    (p["name"], p) for p in expect.__schema__ if p["in"] != "body"
  File "C:\Users\Db0\AppData\Roaming\Python\Python310\site-packages\flask_restx\reqparse.py", line 435, in __schema__
    param = arg.__schema__
  File "C:\Users\Db0\AppData\Roaming\Python\Python310\site-packages\flask_restx\reqparse.py", line 290, in __schema__
    param = {"name": self.name, "in": LOCATIONS.get(self.location, "query")}
TypeError: unhashable type: 'list'

Environment

  • Python version: 3.10.0
  • Flask version: 2.1.3
  • Flask-RESTX version: 0.5.1
  • Other installed Flask extensions: flask_limiter
@db0 db0 added the bug Something isn't working label Sep 22, 2022
@peter-doggart
Copy link
Contributor

I think this is actually a shortfall of Swagger 2.0 rather than flask-restx. We currently use OpenAPI 2.0 to generate the swagger.json file. The Parameter Object specification requires you to set the in: location, which only accepts a single string value:

Field Name: in
Type: string
Description: Required. The location of the parameter. Possible values are "query", "header", "path", "formData" or "body".

If this is just for authorizations, you might want to add them to swagger differently, such as using the build in documenting authorizations fields?

@db0
Copy link
Author

db0 commented Sep 26, 2022

Oh cool. I'll look into that.

nevertheless, according to the documentation, my approach should work as well, no?

@peter-doggart
Copy link
Contributor

Yes, I agree the docs are unclear on this. The actual request parser will work correctly with your code (i.e. it will check both locations for the value), it's just the swagger docs that fail to be generated and that isn't mentioned anywhere currently, and it's all a bit messy!

A workaround I've used in the past is to define a separate API model / reqparser (which you can do with copy() and replace_argument()) for the endpoint with only a single location, but then use the multi-location one in code to actually do the parsing, but obviously that is not ideal either.

The replacement of request parsing / models with something more flexible has been under discussion for a long time on this project too!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants