From 1a550201940637f4fa2d7f6210c922d1b563ead3 Mon Sep 17 00:00:00 2001 From: tkrtmy Date: Mon, 23 Sep 2019 19:17:04 +0900 Subject: [PATCH] typescript-fetch: Add application/x-www-form-urlencoded content support (#3934) * typescript-fetch: to be able to handle application/x-www-form-urlencoded content * typescript-fetch: run typescript-fetch-petstore-all.sh * typescript-fetch: add test's dist dir * typescript-fetch: delete Specified Content-Type header --- .gitignore | 1 + .../resources/typescript-fetch/apis.mustache | 33 +++++++++++--- .../typescript-fetch/runtime.mustache | 15 ++++++- .../builds/default/src/apis/PetApi.ts | 44 +++++++++++++++---- .../builds/default/src/runtime.ts | 15 ++++++- .../builds/es6-target/src/apis/PetApi.ts | 44 +++++++++++++++---- .../builds/es6-target/src/runtime.ts | 15 ++++++- .../multiple-parameters/src/apis/PetApi.ts | 44 +++++++++++++++---- .../builds/multiple-parameters/src/runtime.ts | 15 ++++++- .../src/apis/PetApi.ts | 44 +++++++++++++++---- .../src/runtime.ts | 15 ++++++- .../typescript-three-plus/src/apis/PetApi.ts | 44 +++++++++++++++---- .../typescript-three-plus/src/runtime.ts | 15 ++++++- .../builds/with-interfaces/src/apis/PetApi.ts | 44 +++++++++++++++---- .../builds/with-interfaces/src/runtime.ts | 15 ++++++- .../with-npm-version/src/apis/PetApi.ts | 44 +++++++++++++++---- .../builds/with-npm-version/src/runtime.ts | 15 ++++++- 17 files changed, 392 insertions(+), 70 deletions(-) diff --git a/.gitignore b/.gitignore index 8aee57b0b87..18d2a7a1027 100644 --- a/.gitignore +++ b/.gitignore @@ -174,6 +174,7 @@ samples/client/petstore/python-tornado/.venv/ samples/client/petstore/typescript-angular2/npm/npm-debug.log samples/client/petstore/typescript-node/npm/npm-debug.log samples/client/petstore/typescript-angular/tsd-debug.log +samples/client/petstore/typescript-fetch/tests/**/dist/ # aspnetcore samples/server/petstore/aspnetcore/.vs/ diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache index 57da60ee261..5149d534b8c 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache @@ -150,29 +150,50 @@ export class {{classname}} extends runtime.BaseAPI { {{/isOAuth}} {{/authMethods}} {{#hasFormParams}} - const formData = new FormData(); - {{/hasFormParams}} + const consumes: runtime.Consume[] = [ + {{#consumes}} + { contentType: '{{{mediaType}}}' }, + {{/consumes}} + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + {{#formParams}} + {{#isFile}} + // use FormData to transmit files using content-type "multipart/form-data" + useForm = canConsumeForm; + {{/isFile}} + {{/formParams}} + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + {{#formParams}} {{#isListContainer}} if (requestParameters.{{paramName}}) { {{#isCollectionFormatMulti}} requestParameters.{{paramName}}.forEach((element) => { - formData.append('{{baseName}}', element as any); + formParams.append('{{baseName}}', element as any); }) {{/isCollectionFormatMulti}} {{^isCollectionFormatMulti}} - formData.append('{{baseName}}', requestParameters.{{paramName}}.join(runtime.COLLECTION_FORMATS["{{collectionFormat}}"])); + formParams.append('{{baseName}}', requestParameters.{{paramName}}.join(runtime.COLLECTION_FORMATS["{{collectionFormat}}"])); {{/isCollectionFormatMulti}} } {{/isListContainer}} {{^isListContainer}} if (requestParameters.{{paramName}} !== undefined) { - formData.append('{{baseName}}', requestParameters.{{paramName}} as any); + formParams.append('{{baseName}}', requestParameters.{{paramName}} as any); } {{/isListContainer}} {{/formParams}} + {{/hasFormParams}} const response = await this.request({ path: `{{{path}}}`{{#pathParams}}.replace(`{${"{{baseName}}"}}`, encodeURIComponent(String(requestParameters.{{paramName}}))){{/pathParams}}, method: '{{httpMethod}}', @@ -194,7 +215,7 @@ export class {{classname}} extends runtime.BaseAPI { {{/bodyParam}} {{/hasBodyParam}} {{#hasFormParams}} - body: formData, + body: formParams, {{/hasFormParams}} }); diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/runtime.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/runtime.mustache index 15fca73053f..bd53174f179 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/runtime.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/runtime.mustache @@ -184,7 +184,7 @@ export type Json = any; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS'; export type HTTPHeaders = { [key: string]: string }; export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | HTTPQuery }; -export type HTTPBody = Json | FormData; +export type HTTPBody = Json | FormData | URLSearchParams; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; export interface FetchParams { @@ -231,6 +231,19 @@ export function mapValues(data: any, fn: (item: any) => any) { ); } +export function canConsumeForm(consumes: Consume[]): boolean { + for (const consume of consumes) { + if ('multipart/form-data' === consume.contentType) { + return true; + } + } + return false; +} + +export interface Consume { + contentType: string +} + export interface RequestContext { fetch: FetchAPI; url: string; diff --git a/samples/client/petstore/typescript-fetch/builds/default/src/apis/PetApi.ts b/samples/client/petstore/typescript-fetch/builds/default/src/apis/PetApi.ts index 1fcb27ef1c5..1b59ed3ef08 100644 --- a/samples/client/petstore/typescript-fetch/builds/default/src/apis/PetApi.ts +++ b/samples/client/petstore/typescript-fetch/builds/default/src/apis/PetApi.ts @@ -335,13 +335,26 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'application/x-www-form-urlencoded' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.name !== undefined) { - formData.append('name', requestParameters.name as any); + formParams.append('name', requestParameters.name as any); } if (requestParameters.status !== undefined) { - formData.append('status', requestParameters.status as any); + formParams.append('status', requestParameters.status as any); } const response = await this.request({ @@ -349,7 +362,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.VoidApiResponse(response); @@ -383,13 +396,28 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'multipart/form-data' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + // use FormData to transmit files using content-type "multipart/form-data" + useForm = canConsumeForm; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.additionalMetadata !== undefined) { - formData.append('additionalMetadata', requestParameters.additionalMetadata as any); + formParams.append('additionalMetadata', requestParameters.additionalMetadata as any); } if (requestParameters.file !== undefined) { - formData.append('file', requestParameters.file as any); + formParams.append('file', requestParameters.file as any); } const response = await this.request({ @@ -397,7 +425,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.JSONApiResponse(response, (jsonValue) => ModelApiResponseFromJSON(jsonValue)); diff --git a/samples/client/petstore/typescript-fetch/builds/default/src/runtime.ts b/samples/client/petstore/typescript-fetch/builds/default/src/runtime.ts index eec2074ab69..473d2e72316 100644 --- a/samples/client/petstore/typescript-fetch/builds/default/src/runtime.ts +++ b/samples/client/petstore/typescript-fetch/builds/default/src/runtime.ts @@ -195,7 +195,7 @@ export type Json = any; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS'; export type HTTPHeaders = { [key: string]: string }; export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | HTTPQuery }; -export type HTTPBody = Json | FormData; +export type HTTPBody = Json | FormData | URLSearchParams; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; export interface FetchParams { @@ -242,6 +242,19 @@ export function mapValues(data: any, fn: (item: any) => any) { ); } +export function canConsumeForm(consumes: Consume[]): boolean { + for (const consume of consumes) { + if ('multipart/form-data' === consume.contentType) { + return true; + } + } + return false; +} + +export interface Consume { + contentType: string +} + export interface RequestContext { fetch: FetchAPI; url: string; diff --git a/samples/client/petstore/typescript-fetch/builds/es6-target/src/apis/PetApi.ts b/samples/client/petstore/typescript-fetch/builds/es6-target/src/apis/PetApi.ts index 1fcb27ef1c5..1b59ed3ef08 100644 --- a/samples/client/petstore/typescript-fetch/builds/es6-target/src/apis/PetApi.ts +++ b/samples/client/petstore/typescript-fetch/builds/es6-target/src/apis/PetApi.ts @@ -335,13 +335,26 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'application/x-www-form-urlencoded' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.name !== undefined) { - formData.append('name', requestParameters.name as any); + formParams.append('name', requestParameters.name as any); } if (requestParameters.status !== undefined) { - formData.append('status', requestParameters.status as any); + formParams.append('status', requestParameters.status as any); } const response = await this.request({ @@ -349,7 +362,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.VoidApiResponse(response); @@ -383,13 +396,28 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'multipart/form-data' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + // use FormData to transmit files using content-type "multipart/form-data" + useForm = canConsumeForm; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.additionalMetadata !== undefined) { - formData.append('additionalMetadata', requestParameters.additionalMetadata as any); + formParams.append('additionalMetadata', requestParameters.additionalMetadata as any); } if (requestParameters.file !== undefined) { - formData.append('file', requestParameters.file as any); + formParams.append('file', requestParameters.file as any); } const response = await this.request({ @@ -397,7 +425,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.JSONApiResponse(response, (jsonValue) => ModelApiResponseFromJSON(jsonValue)); diff --git a/samples/client/petstore/typescript-fetch/builds/es6-target/src/runtime.ts b/samples/client/petstore/typescript-fetch/builds/es6-target/src/runtime.ts index eec2074ab69..473d2e72316 100644 --- a/samples/client/petstore/typescript-fetch/builds/es6-target/src/runtime.ts +++ b/samples/client/petstore/typescript-fetch/builds/es6-target/src/runtime.ts @@ -195,7 +195,7 @@ export type Json = any; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS'; export type HTTPHeaders = { [key: string]: string }; export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | HTTPQuery }; -export type HTTPBody = Json | FormData; +export type HTTPBody = Json | FormData | URLSearchParams; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; export interface FetchParams { @@ -242,6 +242,19 @@ export function mapValues(data: any, fn: (item: any) => any) { ); } +export function canConsumeForm(consumes: Consume[]): boolean { + for (const consume of consumes) { + if ('multipart/form-data' === consume.contentType) { + return true; + } + } + return false; +} + +export interface Consume { + contentType: string +} + export interface RequestContext { fetch: FetchAPI; url: string; diff --git a/samples/client/petstore/typescript-fetch/builds/multiple-parameters/src/apis/PetApi.ts b/samples/client/petstore/typescript-fetch/builds/multiple-parameters/src/apis/PetApi.ts index 786513ad7d7..28a239690b8 100644 --- a/samples/client/petstore/typescript-fetch/builds/multiple-parameters/src/apis/PetApi.ts +++ b/samples/client/petstore/typescript-fetch/builds/multiple-parameters/src/apis/PetApi.ts @@ -335,13 +335,26 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'application/x-www-form-urlencoded' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.name !== undefined) { - formData.append('name', requestParameters.name as any); + formParams.append('name', requestParameters.name as any); } if (requestParameters.status !== undefined) { - formData.append('status', requestParameters.status as any); + formParams.append('status', requestParameters.status as any); } const response = await this.request({ @@ -349,7 +362,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.VoidApiResponse(response); @@ -383,13 +396,28 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'multipart/form-data' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + // use FormData to transmit files using content-type "multipart/form-data" + useForm = canConsumeForm; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.additionalMetadata !== undefined) { - formData.append('additionalMetadata', requestParameters.additionalMetadata as any); + formParams.append('additionalMetadata', requestParameters.additionalMetadata as any); } if (requestParameters.file !== undefined) { - formData.append('file', requestParameters.file as any); + formParams.append('file', requestParameters.file as any); } const response = await this.request({ @@ -397,7 +425,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.JSONApiResponse(response, (jsonValue) => ModelApiResponseFromJSON(jsonValue)); diff --git a/samples/client/petstore/typescript-fetch/builds/multiple-parameters/src/runtime.ts b/samples/client/petstore/typescript-fetch/builds/multiple-parameters/src/runtime.ts index eec2074ab69..473d2e72316 100644 --- a/samples/client/petstore/typescript-fetch/builds/multiple-parameters/src/runtime.ts +++ b/samples/client/petstore/typescript-fetch/builds/multiple-parameters/src/runtime.ts @@ -195,7 +195,7 @@ export type Json = any; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS'; export type HTTPHeaders = { [key: string]: string }; export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | HTTPQuery }; -export type HTTPBody = Json | FormData; +export type HTTPBody = Json | FormData | URLSearchParams; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; export interface FetchParams { @@ -242,6 +242,19 @@ export function mapValues(data: any, fn: (item: any) => any) { ); } +export function canConsumeForm(consumes: Consume[]): boolean { + for (const consume of consumes) { + if ('multipart/form-data' === consume.contentType) { + return true; + } + } + return false; +} + +export interface Consume { + contentType: string +} + export interface RequestContext { fetch: FetchAPI; url: string; diff --git a/samples/client/petstore/typescript-fetch/builds/prefix-parameter-interfaces/src/apis/PetApi.ts b/samples/client/petstore/typescript-fetch/builds/prefix-parameter-interfaces/src/apis/PetApi.ts index 1e5dc0803e0..3bd5d9cf411 100644 --- a/samples/client/petstore/typescript-fetch/builds/prefix-parameter-interfaces/src/apis/PetApi.ts +++ b/samples/client/petstore/typescript-fetch/builds/prefix-parameter-interfaces/src/apis/PetApi.ts @@ -335,13 +335,26 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'application/x-www-form-urlencoded' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.name !== undefined) { - formData.append('name', requestParameters.name as any); + formParams.append('name', requestParameters.name as any); } if (requestParameters.status !== undefined) { - formData.append('status', requestParameters.status as any); + formParams.append('status', requestParameters.status as any); } const response = await this.request({ @@ -349,7 +362,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.VoidApiResponse(response); @@ -383,13 +396,28 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'multipart/form-data' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + // use FormData to transmit files using content-type "multipart/form-data" + useForm = canConsumeForm; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.additionalMetadata !== undefined) { - formData.append('additionalMetadata', requestParameters.additionalMetadata as any); + formParams.append('additionalMetadata', requestParameters.additionalMetadata as any); } if (requestParameters.file !== undefined) { - formData.append('file', requestParameters.file as any); + formParams.append('file', requestParameters.file as any); } const response = await this.request({ @@ -397,7 +425,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.JSONApiResponse(response, (jsonValue) => ModelApiResponseFromJSON(jsonValue)); diff --git a/samples/client/petstore/typescript-fetch/builds/prefix-parameter-interfaces/src/runtime.ts b/samples/client/petstore/typescript-fetch/builds/prefix-parameter-interfaces/src/runtime.ts index eec2074ab69..473d2e72316 100644 --- a/samples/client/petstore/typescript-fetch/builds/prefix-parameter-interfaces/src/runtime.ts +++ b/samples/client/petstore/typescript-fetch/builds/prefix-parameter-interfaces/src/runtime.ts @@ -195,7 +195,7 @@ export type Json = any; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS'; export type HTTPHeaders = { [key: string]: string }; export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | HTTPQuery }; -export type HTTPBody = Json | FormData; +export type HTTPBody = Json | FormData | URLSearchParams; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; export interface FetchParams { @@ -242,6 +242,19 @@ export function mapValues(data: any, fn: (item: any) => any) { ); } +export function canConsumeForm(consumes: Consume[]): boolean { + for (const consume of consumes) { + if ('multipart/form-data' === consume.contentType) { + return true; + } + } + return false; +} + +export interface Consume { + contentType: string +} + export interface RequestContext { fetch: FetchAPI; url: string; diff --git a/samples/client/petstore/typescript-fetch/builds/typescript-three-plus/src/apis/PetApi.ts b/samples/client/petstore/typescript-fetch/builds/typescript-three-plus/src/apis/PetApi.ts index 1fcb27ef1c5..1b59ed3ef08 100644 --- a/samples/client/petstore/typescript-fetch/builds/typescript-three-plus/src/apis/PetApi.ts +++ b/samples/client/petstore/typescript-fetch/builds/typescript-three-plus/src/apis/PetApi.ts @@ -335,13 +335,26 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'application/x-www-form-urlencoded' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.name !== undefined) { - formData.append('name', requestParameters.name as any); + formParams.append('name', requestParameters.name as any); } if (requestParameters.status !== undefined) { - formData.append('status', requestParameters.status as any); + formParams.append('status', requestParameters.status as any); } const response = await this.request({ @@ -349,7 +362,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.VoidApiResponse(response); @@ -383,13 +396,28 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'multipart/form-data' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + // use FormData to transmit files using content-type "multipart/form-data" + useForm = canConsumeForm; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.additionalMetadata !== undefined) { - formData.append('additionalMetadata', requestParameters.additionalMetadata as any); + formParams.append('additionalMetadata', requestParameters.additionalMetadata as any); } if (requestParameters.file !== undefined) { - formData.append('file', requestParameters.file as any); + formParams.append('file', requestParameters.file as any); } const response = await this.request({ @@ -397,7 +425,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.JSONApiResponse(response, (jsonValue) => ModelApiResponseFromJSON(jsonValue)); diff --git a/samples/client/petstore/typescript-fetch/builds/typescript-three-plus/src/runtime.ts b/samples/client/petstore/typescript-fetch/builds/typescript-three-plus/src/runtime.ts index 857f5143a6c..aa2ef615892 100644 --- a/samples/client/petstore/typescript-fetch/builds/typescript-three-plus/src/runtime.ts +++ b/samples/client/petstore/typescript-fetch/builds/typescript-three-plus/src/runtime.ts @@ -195,7 +195,7 @@ export type Json = any; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS'; export type HTTPHeaders = { [key: string]: string }; export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | HTTPQuery }; -export type HTTPBody = Json | FormData; +export type HTTPBody = Json | FormData | URLSearchParams; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; export interface FetchParams { @@ -242,6 +242,19 @@ export function mapValues(data: any, fn: (item: any) => any) { ); } +export function canConsumeForm(consumes: Consume[]): boolean { + for (const consume of consumes) { + if ('multipart/form-data' === consume.contentType) { + return true; + } + } + return false; +} + +export interface Consume { + contentType: string +} + export interface RequestContext { fetch: FetchAPI; url: string; diff --git a/samples/client/petstore/typescript-fetch/builds/with-interfaces/src/apis/PetApi.ts b/samples/client/petstore/typescript-fetch/builds/with-interfaces/src/apis/PetApi.ts index 1fcb27ef1c5..1b59ed3ef08 100644 --- a/samples/client/petstore/typescript-fetch/builds/with-interfaces/src/apis/PetApi.ts +++ b/samples/client/petstore/typescript-fetch/builds/with-interfaces/src/apis/PetApi.ts @@ -335,13 +335,26 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'application/x-www-form-urlencoded' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.name !== undefined) { - formData.append('name', requestParameters.name as any); + formParams.append('name', requestParameters.name as any); } if (requestParameters.status !== undefined) { - formData.append('status', requestParameters.status as any); + formParams.append('status', requestParameters.status as any); } const response = await this.request({ @@ -349,7 +362,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.VoidApiResponse(response); @@ -383,13 +396,28 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'multipart/form-data' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + // use FormData to transmit files using content-type "multipart/form-data" + useForm = canConsumeForm; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.additionalMetadata !== undefined) { - formData.append('additionalMetadata', requestParameters.additionalMetadata as any); + formParams.append('additionalMetadata', requestParameters.additionalMetadata as any); } if (requestParameters.file !== undefined) { - formData.append('file', requestParameters.file as any); + formParams.append('file', requestParameters.file as any); } const response = await this.request({ @@ -397,7 +425,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.JSONApiResponse(response, (jsonValue) => ModelApiResponseFromJSON(jsonValue)); diff --git a/samples/client/petstore/typescript-fetch/builds/with-interfaces/src/runtime.ts b/samples/client/petstore/typescript-fetch/builds/with-interfaces/src/runtime.ts index eec2074ab69..473d2e72316 100644 --- a/samples/client/petstore/typescript-fetch/builds/with-interfaces/src/runtime.ts +++ b/samples/client/petstore/typescript-fetch/builds/with-interfaces/src/runtime.ts @@ -195,7 +195,7 @@ export type Json = any; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS'; export type HTTPHeaders = { [key: string]: string }; export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | HTTPQuery }; -export type HTTPBody = Json | FormData; +export type HTTPBody = Json | FormData | URLSearchParams; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; export interface FetchParams { @@ -242,6 +242,19 @@ export function mapValues(data: any, fn: (item: any) => any) { ); } +export function canConsumeForm(consumes: Consume[]): boolean { + for (const consume of consumes) { + if ('multipart/form-data' === consume.contentType) { + return true; + } + } + return false; +} + +export interface Consume { + contentType: string +} + export interface RequestContext { fetch: FetchAPI; url: string; diff --git a/samples/client/petstore/typescript-fetch/builds/with-npm-version/src/apis/PetApi.ts b/samples/client/petstore/typescript-fetch/builds/with-npm-version/src/apis/PetApi.ts index 1fcb27ef1c5..1b59ed3ef08 100644 --- a/samples/client/petstore/typescript-fetch/builds/with-npm-version/src/apis/PetApi.ts +++ b/samples/client/petstore/typescript-fetch/builds/with-npm-version/src/apis/PetApi.ts @@ -335,13 +335,26 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'application/x-www-form-urlencoded' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.name !== undefined) { - formData.append('name', requestParameters.name as any); + formParams.append('name', requestParameters.name as any); } if (requestParameters.status !== undefined) { - formData.append('status', requestParameters.status as any); + formParams.append('status', requestParameters.status as any); } const response = await this.request({ @@ -349,7 +362,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.VoidApiResponse(response); @@ -383,13 +396,28 @@ export class PetApi extends runtime.BaseAPI { } } - const formData = new FormData(); + const consumes: runtime.Consume[] = [ + { contentType: 'multipart/form-data' }, + ]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + // use FormData to transmit files using content-type "multipart/form-data" + useForm = canConsumeForm; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + if (requestParameters.additionalMetadata !== undefined) { - formData.append('additionalMetadata', requestParameters.additionalMetadata as any); + formParams.append('additionalMetadata', requestParameters.additionalMetadata as any); } if (requestParameters.file !== undefined) { - formData.append('file', requestParameters.file as any); + formParams.append('file', requestParameters.file as any); } const response = await this.request({ @@ -397,7 +425,7 @@ export class PetApi extends runtime.BaseAPI { method: 'POST', headers: headerParameters, query: queryParameters, - body: formData, + body: formParams, }); return new runtime.JSONApiResponse(response, (jsonValue) => ModelApiResponseFromJSON(jsonValue)); diff --git a/samples/client/petstore/typescript-fetch/builds/with-npm-version/src/runtime.ts b/samples/client/petstore/typescript-fetch/builds/with-npm-version/src/runtime.ts index eec2074ab69..473d2e72316 100644 --- a/samples/client/petstore/typescript-fetch/builds/with-npm-version/src/runtime.ts +++ b/samples/client/petstore/typescript-fetch/builds/with-npm-version/src/runtime.ts @@ -195,7 +195,7 @@ export type Json = any; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS'; export type HTTPHeaders = { [key: string]: string }; export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | HTTPQuery }; -export type HTTPBody = Json | FormData; +export type HTTPBody = Json | FormData | URLSearchParams; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; export interface FetchParams { @@ -242,6 +242,19 @@ export function mapValues(data: any, fn: (item: any) => any) { ); } +export function canConsumeForm(consumes: Consume[]): boolean { + for (const consume of consumes) { + if ('multipart/form-data' === consume.contentType) { + return true; + } + } + return false; +} + +export interface Consume { + contentType: string +} + export interface RequestContext { fetch: FetchAPI; url: string;