micronaut-projects / micronaut-openapi

Generates OpenAPI / Swagger Documentation for Micronaut projects
https://micronaut-projects.github.io/micronaut-openapi/latest/guide/index.html
Apache License 2.0
80 stars 94 forks source link

Micronaut OpenAPI spec isn't generated correctly #852

Closed bodiam closed 1 year ago

bodiam commented 1 year ago

Expected Behavior

It seems the generation of OpenAPI specifications doesn't take RFC-6570 URI template specification into account.

I have a method in Micronaut which looks like this:

fun checkAvailability(availabilityRequest: AvailabilityRequest): Availability {

My request looks like this:

data class AvailabilityRequest(
    val restaurantId: String,
    val partySize: Int,
    val visitTime: Instant,
)

However, I don't want to pass in a request, I'd like to pass in the individual parameters, such as:

http://localhost/availability?restaurantId=1&partySize=2&visittime=whenever

To do this, I annotated the controller method with this annotation:

@Get("/{?availabilityRequest*}")

(based on the info I found here: https://dzone.com/articles/micronaut-mastery-binding-request-parameters-to-po)

This works well, and all good. But now I want to generate an OpenAPI specification based on the above, and the generation doesn't seem to take the ?availabilityRequest* into account. Instead, it still thinks the availabilityRequest is a parameter, which makes my mocks fail.

The generated OpenAPI spec looks like this:

paths:
  /availability:
    get:
      tags:
      - availability
      summary: Availability check
      description: Returns the available timeslots
      operationId: checkAvailability
      parameters:
      - name: availabilityRequest
        in: query
        required: true
        explode: true
        schema:
          $ref: '#/components/schemas/AvailabilityRequest'

While I expected the OpenAPI spec to look more like this:

paths:
  /availability:
    get:
      tags:
      - availability
      summary: Availability check
      description: Returns the available timeslots
      operationId: checkAvailability
      parameters:
      - name: restaurantId
        in: query
        required: true
        schema:
          type: string
      - name: partySize
        in: query
        required: true
        schema:
          type: integer
          format: int32

Actual Behaviour

See above

Steps To Reproduce

Create a new app with a complex type as input for a Get method (maybe also Post?) Enable openapi Build the spec

Environment Information

MacOS

Example Application

No response

Version

3.7.4

bodiam commented 1 year ago

It seems a workaround for it can be found here (for Spring Boot, but applies to Micronaut too):

https://stackoverflow.com/questions/66053702/springdoc-openapi-with-path-parameters-and-command-object

Annotating the method and explicitly naming the parameters, and then removing the request parameter does it:

    @Parameter(`in` = ParameterIn.PATH, name = "restaurantId", schema = Schema(type = "string"))
    @Parameter(`in` = ParameterIn.PATH, name = "partySize", schema = Schema(type = "int32"))
    fun checkAvailability(@Parameter(hidden = true) availabilityRequest: AvailabilityRequest): Availability {

    }

Generates:

    get:
      tags:
      - availability
      summary: Availability check
      description: Returns the available timeslots
      operationId: checkAvailability
      parameters:
      - name: partySize
        in: path
        required: true
        schema: {}
      - name: restaurantId
        in: path
        required: true
        schema: {}

It's not pretty, but it works. It would be great if this works out of the box though (this has been fixed in Spring Boot / SpringDoc too)

altro3 commented 1 year ago

@bodiam I fixed it in #853