jmcarp / flask-apispec

MIT License
655 stars 156 forks source link

@doc drops explicity set parameters #198

Open marqueewinq opened 4 years ago

marqueewinq commented 4 years ago

Looks like @doc decorator does not respect explicitly set parameters argument.

Steps to reproduce:

from flask import Flask, request
from apispec import APISpec
from apispec.ext.marshmallow import MarshmallowPlugin
from flask_apispec import FlaskApiSpec, MethodResource, doc
from marshmallow import Schema, fields, ValidationError

app = Flask(__name__)

app.config.update(
    {
        "APISPEC_SPEC": APISpec(
            title="Test API",
            version="v0.1",
            plugins=[MarshmallowPlugin()],
            openapi_version="3.0.3",
        ),
        "APISPEC_SWAGGER_UI_URL": "/docs/",
        "APISPEC_SWAGGER_URL": "/swagger/",
    }
)
docs = FlaskApiSpec(app)

class TestSchema(Schema):
    field1 = fields.Str()
    field2 = fields.Str()

class TestResource(MethodResource):
    serializer_class = TestSchema

    @doc(
        parameters=[
            {"in": "body", "name": "body", "schema": serializer_class, "required": True}
        ]
    )
    def get(self):
        data = request.get_json()
        # validate data against serializer_class
        try:
            validated_data = self.serializer_class().load(data)
        except ValidationError as e:
            return {"error": str(e)}, 400
        return TestSchema().dump(validated_data), 200

app.add_url_rule("/", endpoint="testresource", view_func=TestResource.as_view("Test"))
docs.register(TestResource)

if __name__ == "__main__":
    app.run()

Output on /swagger:

{
  "info": {
    "title": "Test API", 
    "version": "v0.1"
  }, 
  "openapi": "3.0.3", 
  "paths": {
    "/": {
      "get": {
        "parameters": [], 
        "responses": {}
      }
    }
  }
}

Expected output:

{
  "info": {
    "title": "Test API", 
    "version": "v0.1"
  }, 
  "openapi": "3.0.3", 
  "paths": {
    "/": {
      "get": {
        "parameters": [{"in": "body", "name": "body", "schema": serializer_class, "required": True}], 
        "responses": {}
      }
    }
  }
}
marqueewinq commented 4 years ago

Note: i am aware that the workaround is using @use_kwargs, but that is really annoying, because

Working example for those who are interested:

from flask import Flask, request
from apispec import APISpec
from apispec.ext.marshmallow import MarshmallowPlugin
from flask_apispec import FlaskApiSpec, MethodResource, doc, use_kwargs
from marshmallow import Schema, fields, ValidationError

app = Flask(__name__)

app.config.update(
    {
        "APISPEC_SPEC": APISpec(
            title="Test API",
            version="v0.1",
            plugins=[MarshmallowPlugin()],
            openapi_version="2.0",
        ),
        "APISPEC_SWAGGER_UI_URL": "/docs/",
        "APISPEC_SWAGGER_URL": "/swagger/",
    }
)
docs = FlaskApiSpec(app)

class TestSchema(Schema):
    field1 = fields.Str()
    field2 = fields.Str()

class TestResource(MethodResource):
    serializer_class = TestSchema

    @use_kwargs(TestSchema, locations=["body"])
    def get(self):
        data = request.get_json()
        # validate data against serializer_class
        try:
            validated_data = self.serializer_class().load(data)
        except ValidationError as e:
            return {"error": str(e)}, 400
        return TestSchema().dump(validated_data), 200

app.add_url_rule("/", endpoint="testresource", view_func=TestResource.as_view("Test"))
docs.register(TestResource)

if __name__ == "__main__":
    app.run()
eberhab commented 3 years ago

It seems someone solved this here: https://github.com/jmcarp/flask-apispec/issues/137 The parameter needs to be called "params" instead of "parameters. It would be nice to find some more documentation about this and how to name the individual parameters, but I can't find anywhere. Did you find out more yourself in the meantime?