acacode / swagger-typescript-api

Generate the API Client for Fetch or Axios from an OpenAPI Specification
MIT License
3.21k stars 351 forks source link

How to use multipart/form-data in NodeJS? #438

Open pedromtcosta opened 1 year ago

pedromtcosta commented 1 year ago

The client gets generated with the createFormData function that is used when the request content is multipart/form-data. The problem is that this function uses the types Blob and File, which are not available in the NodeJS runtime:

protected createFormData(input: Record<string, unknown>): FormData {
  return Object.keys(input || {}).reduce((formData, key) => {
    const property = input[key];
    const propertyContent: any[] = property instanceof Array ? property : [property];

    for (const formItem of propertyContent) {
      const isFileType = formItem instanceof Blob || formItem instanceof File;
      formData.append(key, isFileType ? formItem : this.stringifyFormItem(formItem));
    }

    return formData;
  }, new FormData());
}

using primitiveTypeConstructs to change string.binary from File to Buffer for example does not work for 2 reasons:

Just as a test, I changed the createFormData function to be like the one below and it worked nicely in an API I am testing with, but this is obviously not a good solution:

const isFileType = formItem instanceof Buffer;
protected createFormData(input: Record<string, unknown>): FormData {
  return Object.keys(input || {}).reduce((formData, key) => {
    const property = input[key];
    const propertyContent: any[] = property instanceof Array ? property : [property];

    for (const formItem of propertyContent) {
      const isFileType = formItem instanceof Buffer;
      if (isFileType) {
        formData.append(key, formItem, {filename: 'any.jpeg'});
      } else {
        formData.append(key, this.stringifyFormItem(formItem));
      }
    }

    return formData;
  }, new FormData());
}

so, is it possible to use multipart/form-data in NodeJS?

js2me commented 1 year ago

Hello @pedromtcosta !
Thanks for this question.
Can you describe why your solution is not a good solution in details ?

Just this package is template driven and you can redefine part of swagger schema fields which your swagger schema is using.

Main target for this project is browser, I'm trying to help you how to better create this function createFormData, but I don't know how, sorry. I hope community of this project will help you

Also you can try rewrite fully http-client template as you want

pedromtcosta commented 1 year ago

Hi @js2me !

Basically, the problem with my solution is that I have to provide a file name, which contains the file extension, so generating a "random" name would not work. One thing that could work nicely for this case is if I can somehow map string.binary to be a custom type, so I could do something like:

type MyFile = {
  contents: Buffer
  name: string
}

then the only problem I'd have in this case is that I'd need to change the createFormData function every time I re-generate the client. So I guess my questions at this point would be:

  1. can I map string.binary to a custom type?
  2. can I change how createFormData is generated?