swagger-api / swagger-api/swagger-codegen

[Typescript-Angular] Multipart doesn't appear to handle DTOs properly

Open
#12,065 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Mustache
Stars
17.8k
Forks
6k
PR merge metrics
No merged PRs in 30d

Description

Description

Backend is aspnetcore.
DTOs are not being serialized at all when in a multipart request body.

If doing something like this

public async Task<IActionResult> AddNewTemplateVersionAsync(
        [FromRoute] Guid templateId,
        [FromForm] VersionDataDto versionData,
        [FromForm] IFormFile pdfFile)
{}

I would expect that versionData would be added to the formParams and JSON.stringified, however in this case the dto object is broken up into individual properies as is the file. And nothing is stringified.

If instead this is done

public async Task<IActionResult> AddNewTemplateVersionAsync(
        [FromRoute] Guid templateId,
        [FromBody] VersionDataDto versionData,
        [FromForm] IFormFile pdfFile)
{}

only the dto object shows up in the generated call, the file is ignored. Basically bodyParam is given preference.

If [FromBody] is left out then the dto is assumed to be a query parameter when it isn't and it isn't stringified anyway. The file is however included as the formParams and passed in the body.

My current minor fix for this is to modify the mustache template so that in the case of formParams and a bodyParam, the bodyParam is stringified and added to the formParams, and the order of operations in the http request is flipped so that formParams take precedence over the bodyParam, as body will be included in formParams if both exist. This obviously doesn't fix any of the generated swagger, only the end client calls. Ideally a fix would address all parts.

Swagger-codegen version

3.0.34

Steps to reproduce

Make an api endpoint that utilizes multipart/form-data, e.g. it takes a File, also have it take some DTO. Maybe for the pet store sample project there's an endpoint that allows for an image to be uploaded at the same time a pet object is added, have these in the same api.

Related issues/PRs

Seems related to https://github.com/swagger-api/swagger-codegen/issues/9139

Suggest a fix/enhancement

Modification that allows for the use of FromBody and FromForm in same endpoint. The bodyParam should be appended to the formParams and serialized/stringified, the formParams should take preference in the http request eg.

{{#formParams}}
      {{#isListContainer}}
      if ({{paramName}}) {
      {{#isCollectionFormatMulti}}
          {{paramName}}.forEach((element) => {
              {{#useHttpClient}}formParams = {{/useHttpClient}}formParams.append('{{baseName}}', <any>element){{#useHttpClient}} || formParams{{/useHttpClient}};
          })
      {{/isCollectionFormatMulti}}
      {{^isCollectionFormatMulti}}
          {{#useHttpClient}}formParams = {{/useHttpClient}}formParams.append('{{baseName}}', {{paramName}}.join(COLLECTION_FORMATS['{{collectionFormat}}'])){{#useHttpClient}} || formParams{{/useHttpClient}};
      {{/isCollectionFormatMulti}}
      }
      {{/isListContainer}}
      {{^isListContainer}}
      if ({{paramName}} !== undefined) {
          {{#useHttpClient}}formParams = {{/useHttpClient}}formParams.append('{{baseName}}', <any>{{paramName}}){{#useHttpClient}} || formParams{{/useHttpClient}};
      }
      {{/isListContainer}}
{{/formParams}}
{{#bodyParam}}
      if ({{paramName}} !== undefined && {{paramName}} !== null) {
          {{#useHttpClient}}formParams = {{/useHttpClient}}formParams.append('{{baseName}}', JSON.stringify({{paramName}}));
      }
{{/bodyParam}}

{{/hasFormParams}}
{{#useHttpClient}}
      return this.httpClient.{{httpMethod}}{{^isResponseFile}}<{{#returnType}}{{{returnType}}}{{#isResponseTypeFile}}|undefined{{/isResponseTypeFile}}{{/returnType}}{{^returnType}}any{{/returnType}}>{{/isResponseFile}}(`${this.basePath}{{{path}}}`,{{#isBodyAllowed}}
          {{#hasFormParams}}convertFormParamsToString ? formParams.toString() : formParams{{/hasFormParams}}{{^hasFormParams}}{{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}{{/hasFormParams}},{{/isBodyAllowed}}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the multipart/form-data case with an ASP.NET Core endpoint containing both a DTO and an IFormFile, then inspect the TypeScript-Angular Mustache templates that assemble formParams and bodyParam. Compare the behavior with related issue #9139. Done means the generated client includes the file and JSON-stringifies the DTO in the multipart request, while generated Swagger remains consistent.

Written by the indexing model from the issue text.

Assessment

Tech stack
angular, typescript
Domain
api, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.