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

Wrong path response structure in docs when using OpenAPIv3 #8

Closed
ffarella opened this issue Sep 6, 2018 · 7 comments
Closed

Wrong path response structure in docs when using OpenAPIv3 #8

ffarella opened this issue Sep 6, 2018 · 7 comments
Labels

Comments

@ffarella
Copy link

ffarella commented Sep 6, 2018

Hi,
First of all, thank you so much for this awesome extension! It really fullfills what I need.
I am just facing a little problem. At first i thought it was because i was using a application factory, but then i tried this simple code and I could not generate the openapi.json.
It throws the error TypeError: Object of type 'PetSchema' is not JSON serializable.
It sources back to

File "/flask_app/ext/flask_rest_api/spec/__init__.py", line 78, in _openapi_json
 def _openapi_json(self):
        """Serve JSON spec file"""
        # We don't use Flask.jsonify here as it would sort the keys
        # alphabetically while we want to preserve the order.
        return current_app.response_class(
            json.dumps(self.to_dict(), indent=2),
            mimetype='application/json')

Basically json.dumps fails because it is passed the Marshmallow schema.
Could you please tell me what I do wrong?
Merci beaucoup !!!

app.py:

import marshmallow as ma
from flask import Flask
from flask.views import MethodView

from flask_rest_api import Api, Blueprint

from .config import Config

app = Flask('My API')
app.config.from_object(Config)
api = Api(app)

class Pet:
    pass

api.definition('Pet')


class PetSchema(ma.Schema):

    class Meta:
        strict = True
        ordered = True

    id = ma.fields.Int(dump_only=True)
    name = ma.fields.String()


class PetQueryArgsSchema(ma.Schema):

    class Meta:
        strict = True
        ordered = True

    name = ma.fields.String()


blp = Blueprint(
    'pets', 'pets', url_prefix='/pets',
    description='Operations on pets'
)


@blp.route('/')
class Pets(MethodView):

    @blp.arguments(PetQueryArgsSchema, location='query')
    @blp.response(PetSchema(many=True))
    def get(self, args):
        """List pets"""
        return Pet.get(filters=args)


api.register_blueprint(blp)

config.py

API_VERSION = '1.0.0'
OPENAPI_VERSION = '3.0.0'
OPENAPI_URL_PREFIX = "/apidoc/"
OPENAPI_JSON_PATH = 'openapi.json'
OPENAPI_SWAGGER_UI_PATH = "swagger-ui"
OPENAPI_SWAGGER_UI_VERSION = '3.18.2'

requirements.txt

Flask==1.0.2
flask-rest-api==0.7.0
apispec==0.39.0
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
marshmallow==2.15.4
PyYAML==3.13
webargs==4.0.0
Werkzeug==0.14.1
@ffarella
Copy link
Author

ffarella commented Sep 6, 2018

Nevermind, I tried with changing the version to OPENAPI_VERSION to '2.0' and it now works!
😄

@lafrech
Copy link
Member

lafrech commented Sep 7, 2018

Hi. Thanks for the feedback and the bug report with the test case to reproduce the issue. This is really helpful.

I reworked it a bit.

import marshmallow as ma
from flask import Flask
from flask.views import MethodView

from flask_rest_api import Api, Blueprint


class Config:
    API_VERSION = '1.0.0'
    OPENAPI_VERSION = '3.0.0'
    OPENAPI_URL_PREFIX = "/apidoc/"
    OPENAPI_JSON_PATH = 'openapi.json'
    OPENAPI_SWAGGER_UI_PATH = "swagger-ui"
    OPENAPI_SWAGGER_UI_VERSION = '3.18.2'


app = Flask('My API')
app.config.from_object(Config)
api = Api(app)

class Pet:
    pass

@api.definition('Pet')
class PetSchema(ma.Schema):

    class Meta:
        strict = True
        ordered = True

    id = ma.fields.Int(dump_only=True)
    name = ma.fields.String()


class PetQueryArgsSchema(ma.Schema):

    class Meta:
        strict = True
        ordered = True

    name = ma.fields.String()


blp = Blueprint(
    'pets', 'pets', url_prefix='/pets',
    description='Operations on pets'
)


@blp.route('/')
class Pets(MethodView):

    @blp.arguments(PetQueryArgsSchema, location='query')
    @blp.response(PetSchema(many=True))
    def get(self, args):
        """List pets"""
        return Pet.get(filters=args)


api.register_blueprint(blp)

from pprint import pprint
pprint(api.spec.to_dict())

It is clear from the pprint output that the marshmallow Schema is not resolved.

This is indeed an issue in flask-rest-api.

In OpenAPI v2, the docs read

'responses': {200: {'description': 'Description', 'schema': ... }},

In OpenAPI v3, they read

'responses': {200: {'description': 'Description', 'content': {'application/json': {'schema': ... }},

When using apispec, it is up the the user to use the correct structure in the YAML docstring. Then, apispec being aware of this, it looks in the right place when resolving schemas depending on the OpenAPI version.

When using flask-rest-api, this structure is written by the response decorator. Currently it does things the OpenAPI v2 way, so it is broken for OpenAPI v3. I didn't realized that until now.

This is not trivial to solve as Blueprint can't know the OpenAPI version when its decorators are executed. We'd need to defer the writing of the documentation structure to register_blueprint, when the app object is available.

This needs a bit of refactor. We'd need to store all information is a known internal structure until calling register_views_in_doc where the documentation structure would be created according to the OpenAPI version.

@lafrech lafrech added the bug label Sep 7, 2018
@lafrech lafrech changed the title Marshmallow schema instance passed to json.dumps leads toTypeError: Object of type 'PetSchema' is not JSON serializable Wrong path response structure in docs when using OpenAPIv3 Sep 7, 2018
@lafrech
Copy link
Member

lafrech commented Sep 7, 2018

Also, there's a mistake in your code, the @ is missing before the definition decorator, so the call to the decorator is a no-op.

I fixed it in my version above.

I guess it happened when you minified the example. Anyway, this is not the cause of the problem.

@lafrech lafrech closed this as completed in 2b2b354 Sep 7, 2018
@lafrech
Copy link
Member

lafrech commented Sep 7, 2018

I believe this is fixed in master (not released yet).

Thanks again for the comprehensive bug report.

@lafrech
Copy link
Member

lafrech commented Sep 20, 2018

Fix released in 0.8.0.

@lafrech
Copy link
Member

lafrech commented Sep 21, 2018

Same issue with parameters.

Working on it.

@lafrech
Copy link
Member

lafrech commented Sep 24, 2018

Documentation of requestBody for OpenAPIv3 fixed in master. Not released yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants