Skip to content

Commit e0b2748

Browse files
[typescript-axios] Handle sets as arrays in input parameters (#22642)
* [typescript-axios] Handle sets as arrays in input parameters * Include docstring to explain purpose of replaceWithSerializableTypeIfNeeded function
1 parent 6431383 commit e0b2748

File tree

31 files changed

+273
-65
lines changed

31 files changed

+273
-65
lines changed

modules/openapi-generator/src/main/resources/typescript-axios/api.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import FormData from 'form-data'
1717
{{/withNodeImports}}
1818
// Some imports not used depending on template conditions
1919
// @ts-ignore
20-
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction{{#withAWSV4Signature}}, setAWS4SignatureInterceptor{{/withAWSV4Signature}} } from './common{{importFileExtension}}';
20+
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction, replaceWithSerializableTypeIfNeeded{{#withAWSV4Signature}}, setAWS4SignatureInterceptor{{/withAWSV4Signature}} } from './common{{importFileExtension}}';
2121
import type { RequestArgs } from './base{{importFileExtension}}';
2222
// @ts-ignore
2323
import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base{{importFileExtension}}';

modules/openapi-generator/src/main/resources/typescript-axios/apiInner.mustache

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ export const {{classname}}AxiosParamCreator = function (configuration?: Configur
166166
if ({{paramName}}) {
167167
{{#isCollectionFormatMulti}}
168168
{{#contentType}}
169-
localVarFormParams.append('{{baseName}}', new Blob([JSON.stringify({{paramName}})], { type: "{{contentType}}", }));
169+
localVarFormParams.append('{{baseName}}', new Blob([JSON.stringify({{paramName}}, replaceWithSerializableTypeIfNeeded)], { type: "{{contentType}}", }));
170170
{{/contentType}}
171171
{{^contentType}}
172172
{{paramName}}.forEach((element) => {
@@ -184,7 +184,7 @@ export const {{classname}}AxiosParamCreator = function (configuration?: Configur
184184
localVarFormParams.append('{{baseName}}', {{paramName}} as any);{{/isBoolean}}{{/isPrimitiveType}}{{#isPrimitiveType}}{{#isBoolean}}
185185
localVarFormParams.append('{{baseName}}', String({{paramName}}) as any);{{/isBoolean}}{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isEnumRef}}
186186
localVarFormParams.append('{{baseName}}', {{paramName}} as any);{{/isEnumRef}}{{^isEnumRef}}
187-
localVarFormParams.append('{{baseName}}', new Blob([JSON.stringify({{paramName}})], { type: "application/json", }));{{/isEnumRef}}{{/isPrimitiveType}}{{/multipartFormData}}
187+
localVarFormParams.append('{{baseName}}', new Blob([JSON.stringify({{paramName}}, replaceWithSerializableTypeIfNeeded)], { type: "application/json", }));{{/isEnumRef}}{{/isPrimitiveType}}{{/multipartFormData}}
188188
}{{/isArray}}
189189
{{/formParams}}
190190
{{/vendorExtensions}}
@@ -214,10 +214,10 @@ export const {{classname}}AxiosParamCreator = function (configuration?: Configur
214214
{{#isArray}}
215215
if ({{paramName}}) {
216216
{{#uniqueItems}}
217-
let mapped = Array.from({{paramName}}).map(value => (<any>"{{{dataType}}}" !== "Set<string>") ? JSON.stringify(value) : (value || ""));
217+
let mapped = Array.from({{paramName}}).map(value => (<any>"{{{dataType}}}" !== "Set<string>") ? JSON.stringify(value, replaceWithSerializableTypeIfNeeded) : (value || ""));
218218
{{/uniqueItems}}
219219
{{^uniqueItems}}
220-
let mapped = {{paramName}}.map(value => (<any>"{{{dataType}}}" !== "Array<string>") ? JSON.stringify(value) : (value || ""));
220+
let mapped = {{paramName}}.map(value => (<any>"{{{dataType}}}" !== "Array<string>") ? JSON.stringify(value, replaceWithSerializableTypeIfNeeded) : (value || ""));
221221
{{/uniqueItems}}
222222
localVarHeaderParameter['{{baseName}}'] = mapped.join(COLLECTION_FORMATS["{{collectionFormat}}"]);
223223
}
@@ -232,7 +232,7 @@ export const {{classname}}AxiosParamCreator = function (configuration?: Configur
232232
{{! isString is falsy also for $ref that defines a string or enum type}}
233233
localVarHeaderParameter['{{baseName}}'] = typeof {{paramName}} === 'string'
234234
? {{paramName}}
235-
: JSON.stringify({{paramName}});
235+
: JSON.stringify({{paramName}}, replaceWithSerializableTypeIfNeeded);
236236
{{/isString}}
237237
}
238238
{{/isArray}}

modules/openapi-generator/src/main/resources/typescript-axios/common.mustache

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export const setAWS4SignatureInterceptor = async function (globalAxios: AxiosIns
8080
function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void {
8181
if (parameter == null) return;
8282
if (typeof parameter === "object") {
83-
if (Array.isArray(parameter)) {
83+
if (Array.isArray(parameter) || parameter instanceof Set) {
8484
(parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key));
8585
}
8686
else {
@@ -105,13 +105,26 @@ export const setSearchParams = function (url: URL, ...objects: any[]) {
105105
url.search = searchParams.toString();
106106
}
107107

108+
/**
109+
* JSON serialization helper function which replaces instances of unserializable types with serializable ones.
110+
* This function will run for every key-value pair encountered by JSON.stringify while traversing an object.
111+
* Converting a set to a string will return an empty object, so an intermediate conversion to an array is required.
112+
*/
113+
export const replaceWithSerializableTypeIfNeeded = function(key: any, value: any) {
114+
if (value instanceof Set) {
115+
return Array.from(value);
116+
} else {
117+
return value;
118+
}
119+
}
120+
108121
export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) {
109122
const nonString = typeof value !== 'string';
110123
const needsSerialization = nonString && configuration && configuration.isJsonMime
111124
? configuration.isJsonMime(requestOptions.headers['Content-Type'])
112125
: nonString;
113126
return needsSerialization
114-
? JSON.stringify(value !== undefined ? value : {})
127+
? JSON.stringify(value !== undefined ? value : {}, replaceWithSerializableTypeIfNeeded)
115128
: (value || "");
116129
}
117130

samples/client/echo_api/typescript-axios/build/api.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios';
1818
import globalAxios from 'axios';
1919
// Some imports not used depending on template conditions
2020
// @ts-ignore
21-
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common';
21+
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction, replaceWithSerializableTypeIfNeeded } from './common';
2222
import type { RequestArgs } from './base';
2323
// @ts-ignore
2424
import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base';
@@ -1089,7 +1089,7 @@ export const FormApiAxiosParamCreator = function (configuration?: Configuration)
10891089

10901090

10911091
if (marker !== undefined) {
1092-
localVarFormParams.append('marker', new Blob([JSON.stringify(marker)], { type: "application/json", }));
1092+
localVarFormParams.append('marker', new Blob([JSON.stringify(marker, replaceWithSerializableTypeIfNeeded)], { type: "application/json", }));
10931093
}
10941094
localVarHeaderParameter['Content-Type'] = 'multipart/form-data';
10951095
localVarHeaderParameter['Accept'] = 'text/plain';
@@ -1352,12 +1352,12 @@ export const HeaderApiAxiosParamCreator = function (configuration?: Configuratio
13521352
if (integerHeader != null) {
13531353
localVarHeaderParameter['integer_header'] = typeof integerHeader === 'string'
13541354
? integerHeader
1355-
: JSON.stringify(integerHeader);
1355+
: JSON.stringify(integerHeader, replaceWithSerializableTypeIfNeeded);
13561356
}
13571357
if (booleanHeader != null) {
13581358
localVarHeaderParameter['boolean_header'] = typeof booleanHeader === 'string'
13591359
? booleanHeader
1360-
: JSON.stringify(booleanHeader);
1360+
: JSON.stringify(booleanHeader, replaceWithSerializableTypeIfNeeded);
13611361
}
13621362
if (stringHeader != null) {
13631363
localVarHeaderParameter['string_header'] = String(stringHeader);
@@ -1368,7 +1368,7 @@ export const HeaderApiAxiosParamCreator = function (configuration?: Configuratio
13681368
if (enumRefStringHeader != null) {
13691369
localVarHeaderParameter['enum_ref_string_header'] = typeof enumRefStringHeader === 'string'
13701370
? enumRefStringHeader
1371-
: JSON.stringify(enumRefStringHeader);
1371+
: JSON.stringify(enumRefStringHeader, replaceWithSerializableTypeIfNeeded);
13721372
}
13731373
setSearchParams(localVarUrlObj, localVarQueryParameter);
13741374
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};

samples/client/echo_api/typescript-axios/build/common.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export const setOAuthToObject = async function (object: any, name: string, scope
6666
function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void {
6767
if (parameter == null) return;
6868
if (typeof parameter === "object") {
69-
if (Array.isArray(parameter)) {
69+
if (Array.isArray(parameter) || parameter instanceof Set) {
7070
(parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key));
7171
}
7272
else {
@@ -91,13 +91,26 @@ export const setSearchParams = function (url: URL, ...objects: any[]) {
9191
url.search = searchParams.toString();
9292
}
9393

94+
/**
95+
* JSON serialization helper function which replaces instances of unserializable types with serializable ones.
96+
* This function will run for every key-value pair encountered by JSON.stringify while traversing an object.
97+
* Converting a set to a string will return an empty object, so an intermediate conversion to an array is required.
98+
*/
99+
export const replaceWithSerializableTypeIfNeeded = function(key: any, value: any) {
100+
if (value instanceof Set) {
101+
return Array.from(value);
102+
} else {
103+
return value;
104+
}
105+
}
106+
94107
export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) {
95108
const nonString = typeof value !== 'string';
96109
const needsSerialization = nonString && configuration && configuration.isJsonMime
97110
? configuration.isJsonMime(requestOptions.headers['Content-Type'])
98111
: nonString;
99112
return needsSerialization
100-
? JSON.stringify(value !== undefined ? value : {})
113+
? JSON.stringify(value !== undefined ? value : {}, replaceWithSerializableTypeIfNeeded)
101114
: (value || "");
102115
}
103116

samples/client/others/typescript-axios/with-separate-models-and-api-inheritance/common.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export const setOAuthToObject = async function (object: any, name: string, scope
6666
function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void {
6767
if (parameter == null) return;
6868
if (typeof parameter === "object") {
69-
if (Array.isArray(parameter)) {
69+
if (Array.isArray(parameter) || parameter instanceof Set) {
7070
(parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key));
7171
}
7272
else {
@@ -91,13 +91,26 @@ export const setSearchParams = function (url: URL, ...objects: any[]) {
9191
url.search = searchParams.toString();
9292
}
9393

94+
/**
95+
* JSON serialization helper function which replaces instances of unserializable types with serializable ones.
96+
* This function will run for every key-value pair encountered by JSON.stringify while traversing an object.
97+
* Converting a set to a string will return an empty object, so an intermediate conversion to an array is required.
98+
*/
99+
export const replaceWithSerializableTypeIfNeeded = function(key: any, value: any) {
100+
if (value instanceof Set) {
101+
return Array.from(value);
102+
} else {
103+
return value;
104+
}
105+
}
106+
94107
export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) {
95108
const nonString = typeof value !== 'string';
96109
const needsSerialization = nonString && configuration && configuration.isJsonMime
97110
? configuration.isJsonMime(requestOptions.headers['Content-Type'])
98111
: nonString;
99112
return needsSerialization
100-
? JSON.stringify(value !== undefined ? value : {})
113+
? JSON.stringify(value !== undefined ? value : {}, replaceWithSerializableTypeIfNeeded)
101114
: (value || "");
102115
}
103116

samples/client/petstore/typescript-axios/builds/composed-schemas/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios';
1818
import globalAxios from 'axios';
1919
// Some imports not used depending on template conditions
2020
// @ts-ignore
21-
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common';
21+
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction, replaceWithSerializableTypeIfNeeded } from './common';
2222
import type { RequestArgs } from './base';
2323
// @ts-ignore
2424
import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base';

samples/client/petstore/typescript-axios/builds/composed-schemas/common.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export const setOAuthToObject = async function (object: any, name: string, scope
6666
function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void {
6767
if (parameter == null) return;
6868
if (typeof parameter === "object") {
69-
if (Array.isArray(parameter)) {
69+
if (Array.isArray(parameter) || parameter instanceof Set) {
7070
(parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key));
7171
}
7272
else {
@@ -91,13 +91,26 @@ export const setSearchParams = function (url: URL, ...objects: any[]) {
9191
url.search = searchParams.toString();
9292
}
9393

94+
/**
95+
* JSON serialization helper function which replaces instances of unserializable types with serializable ones.
96+
* This function will run for every key-value pair encountered by JSON.stringify while traversing an object.
97+
* Converting a set to a string will return an empty object, so an intermediate conversion to an array is required.
98+
*/
99+
export const replaceWithSerializableTypeIfNeeded = function(key: any, value: any) {
100+
if (value instanceof Set) {
101+
return Array.from(value);
102+
} else {
103+
return value;
104+
}
105+
}
106+
94107
export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) {
95108
const nonString = typeof value !== 'string';
96109
const needsSerialization = nonString && configuration && configuration.isJsonMime
97110
? configuration.isJsonMime(requestOptions.headers['Content-Type'])
98111
: nonString;
99112
return needsSerialization
100-
? JSON.stringify(value !== undefined ? value : {})
113+
? JSON.stringify(value !== undefined ? value : {}, replaceWithSerializableTypeIfNeeded)
101114
: (value || "");
102115
}
103116

samples/client/petstore/typescript-axios/builds/default/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios';
1818
import globalAxios from 'axios';
1919
// Some imports not used depending on template conditions
2020
// @ts-ignore
21-
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common';
21+
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction, replaceWithSerializableTypeIfNeeded } from './common';
2222
import type { RequestArgs } from './base';
2323
// @ts-ignore
2424
import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base';

samples/client/petstore/typescript-axios/builds/default/common.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export const setOAuthToObject = async function (object: any, name: string, scope
6666
function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void {
6767
if (parameter == null) return;
6868
if (typeof parameter === "object") {
69-
if (Array.isArray(parameter)) {
69+
if (Array.isArray(parameter) || parameter instanceof Set) {
7070
(parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key));
7171
}
7272
else {
@@ -91,13 +91,26 @@ export const setSearchParams = function (url: URL, ...objects: any[]) {
9191
url.search = searchParams.toString();
9292
}
9393

94+
/**
95+
* JSON serialization helper function which replaces instances of unserializable types with serializable ones.
96+
* This function will run for every key-value pair encountered by JSON.stringify while traversing an object.
97+
* Converting a set to a string will return an empty object, so an intermediate conversion to an array is required.
98+
*/
99+
export const replaceWithSerializableTypeIfNeeded = function(key: any, value: any) {
100+
if (value instanceof Set) {
101+
return Array.from(value);
102+
} else {
103+
return value;
104+
}
105+
}
106+
94107
export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) {
95108
const nonString = typeof value !== 'string';
96109
const needsSerialization = nonString && configuration && configuration.isJsonMime
97110
? configuration.isJsonMime(requestOptions.headers['Content-Type'])
98111
: nonString;
99112
return needsSerialization
100-
? JSON.stringify(value !== undefined ? value : {})
113+
? JSON.stringify(value !== undefined ? value : {}, replaceWithSerializableTypeIfNeeded)
101114
: (value || "");
102115
}
103116

0 commit comments

Comments
 (0)