openapi-generator icon indicating copy to clipboard operation
openapi-generator copied to clipboard

[REQ] Allow multiple bodyParams for multiple Content Types in RequestBody

Open jharriman opened this issue 6 years ago • 7 comments

Is your feature request related to a problem? Please describe.

The requestBody specification for OpenAPI 3.0 (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#requestBodyObject) allows you to specify multiple MediaType names and schemas for the Content section of the requestBody.

Leveraging the ability to use multiple MediaTypes in the Content section of the requestBody is quite helpful when your MediaTypes are more meaningful than application/json e.g.

    put:
      operationId: updatePet
      requestBody:
        content:
          application/vnd.petstore.pet.v1+json:
            schema:
              $ref: '#/components/schemas/PetV1'
          application/vnd.petstore.pet.v2+json:
            schema:
              $ref: '#/components/schemas/PetV2'

Unfortunately, the current implementation of openapi-generator assumes that you will only ever specify one MediaType in you content definition:

  • In the fromRequestBody method of DefaultCodegen (https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java#L4776) only the a single CodegenParameter is returned.
  • Looking deeper in the stack, it looks like ModelUtils.getSchemaFromRequestBody and ModelUtils.getSchemaFromContent (https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java#L766) assume that there will only ever be one MediaType. At least an warning is printed letting you know that something is wrong, but that's still unhelpful when you actually want to support multiple MediaTypes in the Content section.

Describe the solution you'd like

It looks like the DefaultCodegen class is already setup to support multiple bodyParams, but the current implementation only ever adds one bodyParam to the list.

Specifically the following changes should be made

  • Parse all possible Content MediaTypes as bodyParams and return a list of CodegenParameter for fromRequestBody
  • Add a new contentType property to the CodegenParameter object to allow generators to know which contentType is associated with each bodyParam

Describe alternatives you've considered

You could alternatively add a property to the consumes object specifying which bodyParam belongs to the listed contentType . . . but that’s means you’d also have to add an identifier to each bodyParam anyway.

jharriman avatar Sep 30 '19 00:09 jharriman

I am also facing the same problem. requestBody: content: application/vnd.api+json: schema: title: convertRequest type: object required: [data] properties: data: type: object properties: templateType: type: string templateVersion: type: string application/octet-stream: schema: title: templateFile type: object properties: templateFile: type: string format: binary application/zip: schema: type: string format: binary

I am getting the following response: > Task :openApiGenerate systemProperties will be renamed to globalProperties in version 5.0 Multiple schemas found in the OAS 'content' section, returning only the first one (application/vnd.api+json) Multiple schemas found in the OAS 'content' section, returning only the first one (application/vnd.api+json) Multiple schemas found in the OAS 'content' section, returning only the first one (application/vnd.api+json) Multiple MediaTypes found, using only the first one

ngarg-panw avatar Jun 18 '20 00:06 ngarg-panw

Hi, any update on this? I am facing the same problem.

nikosmoum avatar Jan 11 '21 15:01 nikosmoum

I am also facing this issue, any updates?

xsw2-2wsx avatar Aug 03 '21 21:08 xsw2-2wsx

I have the same problem with the java generator und jersey2 library. I would be happy if someone could implement this feature, because it occurs in reality.

Malte-Neu avatar Sep 03 '21 11:09 Malte-Neu

same, I've modelled a Spring multipart request that includes a file and json object. Code generates fine once <skipFormModel>false</skipFormModel> is set in the global properties and each parameter is correctly generated with @RequestPart annotations. However the only consumes set is for multipart/form-data as per the request content type when I need application/json generated as well to provide details on the schema object generated. I was going to customise this section in the api.mustache but this does not seem to be possible, either than or i'm not correctly identifying the area in the schema I need to add the vendor extension.

        content:
          multipart/form-data: 
            x-jsonContent: application/json #where to include vendor extension to use in api.mustache???
            schema: # Request payload
              properties:
                fileUploadDto:
                  $ref: "../schemas/maintenance.yml#/components/schemas/FileUploadDto"
                  required:
                    - true
                fileUpload:                  
                  type: string
                  format: binary

Parawata avatar Oct 14 '21 16:10 Parawata

It looks like the necessary core changes were done (request/response header support for multiple content types added in https://github.com/OpenAPITools/openapi-generator/pull/10973 and https://github.com/OpenAPITools/openapi-generator/pull/11046).

Can this also be implemented in the JaxRS/spec generator?

nikosmoum avatar Feb 21 '23 10:02 nikosmoum

My openapi.yaml:

...
    requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeckRequest'
          text/plain:
            schema:
              type: string

Apparently, text/plain is ignored, and the generated api only cares about the json DeckRequest

ldeluigi avatar Aug 26 '24 19:08 ldeluigi

I'm trying to do this for code-gen purposes to make my Ruby API client libraries nicer to use.

Here's my current problem.

     parameter name: :data,
                  in: :body,
                  required: false,

If I set required: false, then my API client users can only call the method like this:

client.copy_template(template_id)
client.copy_template(template_id, data: { parent_folder_id: '123' })
client.copy_template(template_id, data: { parent_folder_id: '123', name: 'new template' })

If I set required: true, then my API client users can only call the method like this:

client.copy_template(template_id, {})
client.copy_template(template_id, parent_folder_id: '123')
client.copy_template(template_id, parent_folder_id: '123', name: 'new template')

The second argument is now required and crashes with an error unless you pass an empty hash. But in Ruby, the surrounding brackets are optional when the last argument is a hash, so the 2nd and 3rd calls still look nice.

apimatic have a really interesting approach: https://docs.apimatic.io/specification-extensions/swagger-codegen-extensions/#multiple-body-parameters-setting

they have a fork where they accept "x-unwrap-body": true to allow multiple optional arguments in method signatures:

"post": {
    "summary": "Multiple body parameters",
    "parameters": [{
        "name": "body",
        "in": "body",
        "required": true,
        "schema": {
            "$ref": "#/definitions/bodySchema"
        }
    }],
    "x-unwrap-body": true
}

If openapi-generator supported "x-unwrap-body": true or had a way to enable it for all operators, then my client users could do this:

client.copy_template(template_id)
client.copy_template(template_id, parent_folder_id: '123')
client.copy_template(template_id, parent_folder_id: '123', name: 'new template')

I'm not sure how this works for other programming languages, but this looks much nicer in Ruby.

ndbroadbent avatar Feb 15 '25 05:02 ndbroadbent