swagger-api / swagger-core

Examples and server integrations for generating the Swagger API Specification, which enables easy access to your REST API
http://swagger.io
Apache License 2.0
7.36k stars 2.17k forks source link

ArraySchema with anyOf is setting type of the items to "string" #4624

Open NiFNi opened 4 months ago

NiFNi commented 4 months ago

Hi!

I am using Spring Boot (3.2.3) with springdoc-openapi-starter-webmvc-ui (2.2.20). I have a controller annotated like this:

    @ApiResponse(responseCode = "200",
            content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                    array = @ArraySchema(schema = @Schema(anyOf = {
                            Dto1.class,
                            Dto2.class
                    }))))
    @GetMapping
    public List<? extends AbstractDto> get() {
        return List.of();
    }

This results in an API specification looking like this:

{
    "openapi": "3.0.1",
    "info": {
        "title": "OpenAPI definition",
        "version": "v0"
    },
    "servers": [
        {
            "url": "http://localhost:8080",
            "description": "Generated server url"
        }
    ],
    "paths": {
        "/": {
            "get": {
                "tags": [
                    "controller"
                ],
                "operationId": "get_1",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "type": "string",
                                        "anyOf": [
                                            {
                                                "$ref": "#/components/schemas/Dto1"
                                            },
                                            {
                                                "$ref": "#/components/schemas/Dto2"
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "Dto1": {
                "type": "object"
            },
            "Dto2": {
                "type": "object"
            }
        }
    }
}

As you can see the type of the items in the array is set to string which looks wrong and also results in swagger-ui rendering the API wrong. Tracking the code led me to this line which sets the type to "string": https://github.com/swagger-api/swagger-core/blob/3fcc473c33c56f306902853a451020926ad691ea/modules/swagger-core/src/main/java/io/swagger/v3/core/util/AnnotationsUtils.java#L1745

I don't really understand why this is done. As a workaround to get it working correctly I added an explicit type to the items like this which atleast makes swagger-ui render the anyOf correctly:

    @ApiResponse(responseCode = "200",
            content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                    array = @ArraySchema(schema = @Schema(anyOf = {
                            Dto1.class,
                            Dto2.class
                    }, type = "object"))))
    @GetMapping
    public List<? extends AbstractDto> get() {
        return List.of();
    }

What I would have expected in the first place is that the type is not added to the items at all if an anyOf is included.