marshmallow-code / apispec

A pluggable API specification generator. Currently supports the OpenAPI Specification (f.k.a. the Swagger specification)..
https://apispec.readthedocs.io/
MIT License
1.18k stars 177 forks source link

Incorrect handling of nested schemas where `nullable=True` and has description #955

Open luhn opened 2 weeks ago

luhn commented 2 weeks ago

953 changed how nullable nested schemas were handled, to fix #952.

It seems that the old behavior is still present if you set a description in the metadata field.

from apispec import APISpec

from apispec.ext.marshmallow import MarshmallowPlugin
from marshmallow import Schema, fields

spec = APISpec(
    title="Test",
    version="1.0.0",
    openapi_version="3.0.2",
    plugins=[MarshmallowPlugin()],
)

class NestedSchema(Schema):
    id = fields.Int()

class TestSchema(Schema):
    id = fields.Int()
    nested = fields.Nested(NestedSchema, allow_none=True)
    nested_with_description = fields.Nested(
        NestedSchema,
        allow_none=True,
        metadata={'description': 'Foobar'},
    )

spec.components.schema("Test", schema=TestSchema)
print(spec.to_yaml())

Output:

paths: {}
info:
  title: Test
  version: 1.0.0
openapi: 3.0.2
components:
  schemas:
    Nested:
      type: object
      properties:
        id:
          type: integer
    Test:
      type: object
      properties:
        id:
          type: integer
        nested:
          anyOf:
          - type: object
            nullable: true
          - $ref: '#/components/schemas/Nested'
        nested_with_description:
          description: Foobar
          allOf:
          - $ref: '#/components/schemas/Nested'
          nullable: true

I would expect that nested and nested_with_description would be identical except for the description field, but you can see that nested_with_description has the behavior that was deemed incorrect in #952.

luhn commented 2 weeks ago

Interestingly if I bump the OpenAPI version to 3.1.1, it doesn't appear to have the same issue.

paths: {}
info:
  title: Test
  version: 1.0.0
openapi: 3.1.1
components:
  schemas:
    Nested:
      type: object
      properties:
        id:
          type: integer
    Test:
      type: object
      properties:
        id:
          type: integer
        nested:
          anyOf:
          - $ref: '#/components/schemas/Nested'
          - type: 'null'
        nested_with_description:
          description: Foobar
          anyOf:
          - $ref: '#/components/schemas/Nested'
          - type: 'null'
lafrech commented 2 weeks ago

Thanks for reporting. Would you like to investigate this and propose a fix?