diff --git a/.changeset/gentle-pets-clean.md b/.changeset/gentle-pets-clean.md new file mode 100644 index 000000000..b36ebf36b --- /dev/null +++ b/.changeset/gentle-pets-clean.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-ts": patch +--- + +fix(axios): use builtin form data to ensure blob form data works in node environment diff --git a/src/templates/core/axios/request.hbs b/src/templates/core/axios/request.hbs index 70286f5b9..ec66438f0 100644 --- a/src/templates/core/axios/request.hbs +++ b/src/templates/core/axios/request.hbs @@ -32,6 +32,9 @@ import type { OpenAPIConfig } from './OpenAPI'; {{>functions/getUrl}} +{{>functions/getFormData}} + + {{>functions/resolve}} @@ -65,7 +68,7 @@ export const request = (config: OpenAPIConfig, options: ApiRequestOptions, ax return new CancelablePromise(async (resolve, reject, onCancel) => { try { const url = getUrl(config, options); - const formData = options.formData; + const formData = getFormData(options.formData); const body = getRequestBody(options); const headers = await getHeaders(config, options); diff --git a/src/templates/core/axios/sendRequest.hbs b/src/templates/core/axios/sendRequest.hbs index a9280a999..559c8d0b0 100644 --- a/src/templates/core/axios/sendRequest.hbs +++ b/src/templates/core/axios/sendRequest.hbs @@ -3,7 +3,7 @@ export const sendRequest = async ( options: ApiRequestOptions, url: string, body: unknown, - formData: Record | undefined, + formData: FormData | undefined, headers: Record, onCancel: OnCancel, axiosClient: AxiosInstance diff --git a/test/__snapshots__/v3_axios/core/request.ts.snap b/test/__snapshots__/v3_axios/core/request.ts.snap index 1687097d0..590a9f862 100644 --- a/test/__snapshots__/v3_axios/core/request.ts.snap +++ b/test/__snapshots__/v3_axios/core/request.ts.snap @@ -79,6 +79,33 @@ const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => { return options.query ? url + getQueryString(options.query) : url; }; +export const getFormData = (options: ApiRequestOptions): FormData | undefined => { + if (options.formData) { + const formData = new FormData(); + + const process = (key: string, value: unknown) => { + if (isString(value) || isBlob(value)) { + formData.append(key, value); + } else { + formData.append(key, JSON.stringify(value)); + } + }; + + Object.entries(options.formData) + .filter(([, value]) => value !== undefined && value !== null) + .forEach(([key, value]) => { + if (Array.isArray(value)) { + value.forEach(v => process(key, v)); + } else { + process(key, value); + } + }); + + return formData; + } + return undefined; +}; + type Resolver = (options: ApiRequestOptions) => Promise; export const resolve = async (options: ApiRequestOptions, resolver?: T | Resolver): Promise => { @@ -288,7 +315,7 @@ export const request = ( return new CancelablePromise(async (resolve, reject, onCancel) => { try { const url = getUrl(config, options); - const formData = options.formData; + const formData = getFormData(options.formData); const body = getRequestBody(options); const headers = await getHeaders(config, options);