question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Multipart/form-data with two parts does not generate correct typescript

See original GitHub issue

I have a C# method (prototype below) that contains one Object to be serialized to JSON and one file upload. No matter what option I try (JSON object as Form Data or as Body data), the JSON object is either not valid or not part of the generated typescript. This is using version 11.12.9.

When using [FromData] to incorporate the object as a multipart form, the generated typescript calls toString() on the object, which uses the Object prototype and therefore adds [object Object] to the call, which is not valid.

When using [FromBody] for the object, the object is entirely ignored by the generated typescript. It is part of the method signature but is never added to the HTTP request.

Providing method signature, Swagger JSON, and output Typescript below for reference.

Prototype

[HttpPost]
[AllowAnonymous]
[Consumes("multipart/form-data")]
[ActionName("applyForJob")]
[SwaggerResponse((int)HttpStatusCode.OK, null)]
[SwaggerResponse((int)HttpStatusCode.BadRequest, typeof(void))]
public async Task<IActionResult> ApplyForJob(
      [FromForm] JobApplicationModel jobModel,
      [FromForm] IFormFile resume)

Swagger

"/api/Contact/applyForJob": {
      "post": {
        "tags": [
          "Contact"
        ],
        "operationId": "Contact_applyForJob",
        "consumes": [
          "multipart/form-data"
        ],
        "parameters": [
          {
            "type": "object",
            "name": "jobModel",
            "in": "formData",
            "x-schema": {
              "$ref": "#/definitions/JobApplicationModel"
            },
            "x-nullable": true
          },
          {
            "type": "file",
            "name": "resume",
            "in": "formData",
            "x-nullable": true
          }
        ],
        "responses": {
          "200": {
            "description": ""
          },
          "400": {
            "description": ""
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },

Typescript

apiContactApplyforjob(jobModel: JobApplicationModel | null, resume: FileParameter | null): Observable<void> {
        let url_ = this.baseUrl + "/api/Contact/applyForJob";
        url_ = url_.replace(/[?&]$/, "");

        const content_ = new FormData();
        if (jobModel !== null && jobModel !== undefined)
            content_.append("jobModel", jobModel.toString());
        if (resume !== null && resume !== undefined)
            content_.append("resume", resume.data, resume.fileName ? resume.fileName : "resume");
....[snipped for clarity]

Issue Analytics

  • State:open
  • Created 6 years ago
  • Reactions:18
  • Comments:12 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
EugenRajkoviccommented, May 19, 2020

@jonmill I run into the same problem as you described and manage to go around it by overriding toString() method of that specific type.

import * as generated from "./Client";

class CreateEditViewModel extends generated.CreateEditViewModel {
        public toString() {
        return JSON.stringify(this);
     }
}

I used this as guidance https://github.com/RicoSuter/NJsonSchema/wiki/TypeScriptGenerator#extended-classes-and-extension-code

Hope this will help somebody in the same boat!

1reaction
jnsncommented, Sep 3, 2020

Any update on this? I am still experiencing this using version 13.7.0.

C# code
public async Task<ActionResult<CreateProjectResponse>> Create(
    [FromBody] CreateProjectRequest request, 
    IFormFile previewImage, 
    List<IFormFile> images)
Generated TypeScript
create(request: CreateProjectRequest, previewImage: FileParameter | null | undefined, images: FileParameter[] | null | undefined): Observable<CreateProjectResponse> {
        let url_ = this.baseUrl + "/api/v1/projects";
        url_ = url_.replace(/[?&]$/, "");

        const content_ = new FormData();
        if (previewImage !== null && previewImage !== undefined)
            content_.append("previewImage", previewImage.data, previewImage.fileName ? previewImage.fileName : "previewImage");
        if (images !== null && images !== undefined)
            images.forEach(item_ => content_.append("images", item_.data, item_.fileName ? item_.fileName : "images") );

        let options_ : any = {
            body: content_,
            observe: "response",
            responseType: "blob",
            headers: new HttpHeaders({
                "Content-Type": "application/json",
                "Accept": "application/json"
            })
        };

        return this.http.request("post", url_, options_).pipe(_observableMergeMap((response_ : any) => {
            return this.processCreate(response_);
        })).pipe(_observableCatch((response_: any) => {
            if (response_ instanceof HttpResponseBase) {
                try {
                    return this.processCreate(<any>response_);
                } catch (e) {
                    return <Observable<CreateProjectResponse>><any>_observableThrow(e);
                }
            } else
                return <Observable<CreateProjectResponse>><any>_observableThrow(response_);
        }));
    }

As you can see, the request: CreateProjectRequest is part of the generated method, but it’s never used anywhere in the body of the method and never added to the form data.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Multipart/form-data with two parts does not generate correct ...
I have a C# method (prototype below) that contains one Object to be serialized to JSON and one file upload. No matter what...
Read more >
Composing multipart/form-data with a different Content- ...
According to the documentation of FormData , you can append a field with a specific content type by using the Blob constructor:
Read more >
Sending HTTP requests, understanding multipart/form-data
This article presents the way to make HTTP requests in pure Node.js. Other viable solution is using a library like axios. Node.js TypeScript: ......
Read more >
Setting Content-Type for multipart/form-data values
I was recently creating a form that submitted two elements at once: a JSON payload, and a file. My back-end kept choking on...
Read more >
Express multer middleware
js middleware for handling multipart/form-data , which is primarily used for uploading files. It is written on top of busboy for maximum efficiency....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found