jmcarp / flask-apispec

MIT License
655 stars 156 forks source link

openapi_version=3.0.0. -> curl dow not get body at 'try it out' at 'execution' #218

Open muffmolch opened 3 years ago

muffmolch commented 3 years ago

Version 2.0.0

 curl` -X POST "http://textors-01:5000/smanlagen" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"name\": \"string\", \"smobjekt_objid\": 0, \"smobjekt_uuid\": \"string\", \"smserver_id\": \"string\"}"

vs. Version 3.0.0

curl -X POST "http://textors-01:5000/smanlagen" -H "accept: */*"

is this a bug of this package or some related package?

zastruga commented 3 years ago

Just found the same issue. Why on earth does the Content-Type header get set when using the 2.x spec but not with OpenAPI v3.x!?

tabebqena commented 3 years ago

I have the same issue with version=3.0.2

tabebqena commented 3 years ago

This is becouse in version 3 , there is a new object requestBody, it is equivalent in version 2 to the parameters of parameter in=body. This parameter type was removed in version > 3.0.0. But flask-apispec still parse the schema with 'in=body'.

muffmolch commented 3 years ago

Thus this is a bug :-(

quanengineering commented 3 years ago

Here's a dirty fix, please correct me if there's a better way:

    def get_operation(self, rule, view, parent=None):
        annotation = resolve_annotations(view, 'docs', parent)
        docs = merge_recursive(annotation.options)
        operation = {
            'responses': self.get_responses(view, parent),
            'parameters': self.get_parameters(rule, view, docs, parent),
        }
        request_body = self.get_request_body(rule, view, docs, parent)
        if request_body:
            operation['requestBody'] = request_body
        docs.pop('params', None)
        return merge_recursive([operation, docs])

    def get_request_body(self, rule, view, docs, parent=None):
        openapi = self.marshmallow_plugin.converter
        annotation = resolve_annotations(view, 'args', parent)
        request_body = {}
        for args in annotation.options:
            schema = args.get('args', {})
            openapi_converter = openapi.schema2parameters
            if not is_instance_or_subclass(schema, Schema):
                if callable(schema):
                    schema = schema(request=None)
                else:
                    schema = Schema.from_dict(schema)
                    openapi_converter = functools.partial(
                        self._convert_dict_schema, openapi_converter)

            options = copy.copy(args.get('kwargs', {}))
            if not options.get('location'):
                options['location'] = 'body'
            if self.spec.openapi_version.major > 2 and options['location'] == 'body':
                request_body = openapi_converter(schema, **options) if args else []
                if request_body:
                    request_body = {
                        "content": {"application/json": {'schema': extra_params[0]['schema']}}
                    }
        return request_body

    def get_parameters(self, rule, view, docs, parent=None):
        openapi = self.marshmallow_plugin.converter
        annotation = resolve_annotations(view, 'args', parent)
        extra_params = []
        for args in annotation.options:
            schema = args.get('args', {})
            openapi_converter = openapi.schema2parameters
            if not is_instance_or_subclass(schema, Schema):
                if callable(schema):
                    schema = schema(request=None)
                else:
                    schema = Schema.from_dict(schema)
                    openapi_converter = functools.partial(
                        self._convert_dict_schema, openapi_converter)

            options = copy.copy(args.get('kwargs', {}))
            if not options.get('location'):
                options['location'] = 'body'
            if not (self.spec.openapi_version.major > 2 and options['location'] == 'body'):
                extra_params += openapi_converter(schema, **options) if args else []

        rule_params = rule_to_params(rule, docs.get('params'), major_api_version=self.spec.openapi_version.major) or []

        return extra_params + rule_params
carlos-ventura-fo commented 1 year ago

Any ETA on fixing body being inside parameters and not under Request body?