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

duplicated mapping key - support for different content types on the same path & method #28

Open
Robbilie opened this issue Jun 16, 2020 · 8 comments

Comments

@Robbilie
Copy link

currently when writing a controller with different methods for the same path but different content-types the resulting openapi.yml is invalid since it will generate two entries of the same method instead of reusing the same method and just adding the second content type.

example:
expected result:

openapi: 3.0.0
info:
  title: "openapi-v3-test"
  version: "0.0.1-SNAPSHOT"
  description: "<h1>openapi-v3-test</h1><p>Test for th use of openapi v3</p>"
  license:
    name: "Apache License, Version 2.0"
    url: "https://www.apache.org/licenses/LICENSE-2.0"
servers: []
paths:
  "/hello/world":
    get:
      description: "Gets a list of vehicle functions by calling the operation list for the vehicle and merging it with the service\nconfiguration data from the AEM config service."
      tags:
        - "Hello"
      summary: "Gets a list of vehicle functions by calling the operation list for the vehicle and merging it with the service\nconfiguration data from the AEM config service."
      deprecated: false
      operationId: sayHelloV1
      parameters:
      - name: "Accept-Language"
        in: header
        description: "Standard HTTP Accept-Language header"
        required: false
        schema:
          type: string
        style: simple
      responses:
        "200":
          description: "Success"
          content:
            "application/json+v1":
              schema:
                description: "Success"
                type: string
            "application/json+v2":
              schema:
                description: "Success"
                type: string
components: {}

actual result:

openapi: 3.0.0
info:
  title: "openapi-v3-test"
  version: "0.0.1-SNAPSHOT"
  description: "<h1>openapi-v3-test</h1><p>Test for th use of openapi v3</p>"
  license:
    name: "Apache License, Version 2.0"
    url: "https://www.apache.org/licenses/LICENSE-2.0"
servers: []
paths:
  "/hello/world":
    get:
      description: "Gets a list of vehicle functions by calling the operation list for the vehicle and merging it with the service\nconfiguration data from the AEM config service."
      tags:
        - "Hello"
      summary: "Gets a list of vehicle functions by calling the operation list for the vehicle and merging it with the service\nconfiguration data from the AEM config service."
      deprecated: false
      operationId: sayHelloV1
      parameters:
      - name: "Accept-Language"
        in: header
        description: "Standard HTTP Accept-Language header"
        required: false
        schema:
          type: string
        style: simple
      responses:
        "200":
          description: "Success"
          content:
            "application/json+v1":
              schema:
                description: "Success"
                type: string
            "application/json+v2":
              schema:
                description: "Success"
                type: string
 
    get:
      description: "Gets a list of vehicle functions by calling the operation list for the vehicle and merging it with the service\nconfiguration data from the AEM config service."
      tags:
        - "Hello"
      summary: "Gets a list of vehicle functions by calling the operation list for the vehicle and merging it with the service\nconfiguration data from the AEM config service."
      deprecated: false
      operationId: sayHelloV2
      parameters:
      - name: "Accept-Language"
        in: header
        description: "Standard HTTP Accept-Language header"
        required: false
        schema:
          type: string
        style: simple
      responses:
        "200":
          description: "Success"
          content:
            "application/json+v2":
              schema:
                description: "Success"
                type: string
 
components: {}
@jskov-jyskebank-dk
Copy link
Collaborator

That should be easy to fix. But I do not have the time to do it myself right now.
If you can fix it yourself, I will be happy to accept the PR.

@jskov-jyskebank-dk
Copy link
Collaborator

@Robbilie This may be fixed by @bkratz 's changes in 1.1.5
If so, please close this issue. Ta!

@m4h3
Copy link

m4h3 commented May 11, 2021

hitting this problem with 1.1.5.
AFAIK @bkratz changes were related to expanding @Consumes/@produces for 1 method.
Here there is multiple methods, one for each content type.

@bkratz
Copy link
Contributor

bkratz commented May 14, 2021

@Robbilie Could you provide some sample code. Since it is a difference, whether you have "different methods for the same path but different content-types" (as stated in your description) or one method for two different content-types (as also stated in your description).
For the first case, the actual result is absolutely correct, since you have one path and 2 'get' definitions with different 'operationId' representing the different methods.

@Robbilie
Copy link
Author

"absolutely correct" in what sense? Certainly not in the sense of "valid open API yaml" :)

Errors
Hide
 
Parser error duplicated mapping key
Jump to line 40

@bkratz
Copy link
Contributor

bkratz commented May 18, 2021

OK, I take back my sentence stating that the generated yaml is correct.

But the to be able to help you, could you provide some sample code of your controller.
You seem to have 2 controller methods for the path "/hello/world", one named "sayHelloV1" and one named "sayHelloV2".
Maybe this is helpful, especially the comment from Damon Sutherland.
Also have a look here.

@Robbilie
Copy link
Author

@RestController
public interface VehicleFunctionsController {

    @GetMapping(value = {"/vehicles/{vin}/services"}, produces = {"application/vnd.example.functionlist.v3+json",
            "application/vnd.example.error.v1+json"})
    @Operation(description = "Gets a list of vehicle functions by calling the operation list for the vehicle and merging it with the service configuration data from the AEM config service.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Success", content = @Content(
                    mediaType = "application/vnd.example.functionlist.v3+json",
                    schema = @Schema(implementation = VehicleFunctionsListV3.class))),
            @ApiResponse(responseCode = "403", description = "user is non paired guest user / anonymous and is not owner", content = @Content(
                    mediaType = "application/vnd.example.error.v1+json",
                    schema = @Schema(implementation = ExceptionResponseMessage.class))),
            @ApiResponse(responseCode = "500", description = "Internal error during request execution", content = @Content(
                    mediaType = "application/vnd.example.error.v1+json",
                    schema = @Schema(implementation = ExceptionResponseMessage.class)))
    })
    ResponseEntity<?> listFunctions(
            @Parameter(description = "Standard HTTP Accept-Language header")
            @NotNull @RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) String acceptLanguage,
            @Parameter(description = "Bearer access token")
            @NotNull @RequestHeader(HttpHeaders.AUTHORIZATION) String authorization,
            @Parameter(description = "The VIN of the vehicle")
            @NotNull @PathVariable(Headers.VIN) String vin);


    @GetMapping(value = {"/vehicles/{vin}/services"}, produces = {"application/vnd.example.functionlist.v2+json",
            "application/vnd.example.error.v1+json"})
    @Operation(description = "Gets a list of vehicle functions by calling the operation list for the vehicle and merging it with the service configuration data from the AEM config service.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Success", content = @Content(
                    mediaType = "application/vnd.example.functionlist.v2+json",
                    schema = @Schema(implementation = VehicleFunctionsListV2.class))),
            @ApiResponse(responseCode = "403", description = "user is non paired guest user / anonymous and is not owner", content = @Content(
                    mediaType = "application/vnd.example.error.v1+json",
                    schema = @Schema(implementation = ExceptionResponseMessage.class))),
            @ApiResponse(responseCode = "500", description = "Internal error during request execution", content = @Content(
                    mediaType = "application/vnd.example.error.v1+json",
                    schema = @Schema(implementation = ExceptionResponseMessage.class)))
    })
    ResponseEntity<?> listFunctionsV2(
            @Parameter(description = "Standard HTTP Accept-Language header")
            @NotNull @RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) String acceptLanguage,
            @Parameter(description = "Bearer access token")
            @NotNull @RequestHeader(HttpHeaders.AUTHORIZATION) String authorization,
            @Parameter(description = "The VIN of the vehicle")
            @NotNull @PathVariable(Headers.VIN) String vin);


    @GetMapping(value = {"/vehicles/{vin}/services"}, produces = {"application/json",
            "application/vnd.example.functionlist.v1+json", "application/vnd.example.error.v1+json"})
    @Operation(description = "Gets a list of vehicle functions by calling the operation list for the vehicle and merging it with the service configuration data from the AEM config service.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Success", content = @Content(
                    mediaType = "application/vnd.example.functionlist.v1+json",
                    schema = @Schema(implementation = VehicleFunctionsListV1.class))),
            @ApiResponse(responseCode = "200", description = "Success", content = @Content(
                    mediaType = "application/json",
                    schema = @Schema(implementation = VehicleFunctionsListV1.class))),
            @ApiResponse(responseCode = "403", description = "user is non paired guest user / anonymous and is not owner", content = @Content(
                    mediaType = "application/vnd.example.error.v1+json",
                    schema = @Schema(implementation = ExceptionResponseMessage.class))),
            @ApiResponse(responseCode = "500", description = "Internal error during request execution", content = @Content(
                    mediaType = "application/vnd.example.error.v1+json",
                    schema = @Schema(implementation = ExceptionResponseMessage.class)))
    })
    ResponseEntity<?> listFunctionsV1(
            @Parameter(description = "Standard HTTP Accept-Language header")
            @NotNull @RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) String acceptLanguage,
            @Parameter(description = "Bearer access token")
            @NotNull @RequestHeader(HttpHeaders.AUTHORIZATION) String authorization,
            @Parameter(description = "The VIN of the vehicle")
            @NotNull @PathVariable(Headers.VIN) String vin);

}

@m4h3
Copy link

m4h3 commented Jul 26, 2021

any update on this ?

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

No branches or pull requests

4 participants