diff --git a/modules/openapi-generator/src/main/resources/typescript-angular/api.base.service.mustache b/modules/openapi-generator/src/main/resources/typescript-angular/api.base.service.mustache index 87f4b24cce78..77c9e20e1f99 100644 --- a/modules/openapi-generator/src/main/resources/typescript-angular/api.base.service.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-angular/api.base.service.mustache @@ -45,7 +45,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/modules/openapi-generator/src/test/resources/3_0/query-param-json.yaml b/modules/openapi-generator/src/test/resources/3_0/query-param-json.yaml index a943c346040e..e07c13b0cdff 100644 --- a/modules/openapi-generator/src/test/resources/3_0/query-param-json.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/query-param-json.yaml @@ -15,6 +15,17 @@ paths: application/json: schema: $ref: '#/components/schemas/Filter' + - in: query + name: tags + description: Tags + required: false + content: + application/json: + schema: + type: array + items: + type: string + uniqueItems: true responses: '200': diff --git a/samples/client/others/typescript-angular-v20/builds/query-param-deep-object/api.base.service.ts b/samples/client/others/typescript-angular-v20/builds/query-param-deep-object/api.base.service.ts index 6999fb69b2e5..8ef269180c91 100644 --- a/samples/client/others/typescript-angular-v20/builds/query-param-deep-object/api.base.service.ts +++ b/samples/client/others/typescript-angular-v20/builds/query-param-deep-object/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/others/typescript-angular-v20/builds/query-param-form-dot/api.base.service.ts b/samples/client/others/typescript-angular-v20/builds/query-param-form-dot/api.base.service.ts index 497c080d6fd7..a5ce96389fe9 100644 --- a/samples/client/others/typescript-angular-v20/builds/query-param-form-dot/api.base.service.ts +++ b/samples/client/others/typescript-angular-v20/builds/query-param-form-dot/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/others/typescript-angular-v20/builds/query-param-form/api.base.service.ts b/samples/client/others/typescript-angular-v20/builds/query-param-form/api.base.service.ts index 312f99d4c190..3128dffcb8dc 100644 --- a/samples/client/others/typescript-angular-v20/builds/query-param-form/api.base.service.ts +++ b/samples/client/others/typescript-angular-v20/builds/query-param-form/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/others/typescript-angular-v20/builds/query-param-json/api.base.service.ts b/samples/client/others/typescript-angular-v20/builds/query-param-json/api.base.service.ts index 7fe22193a2c1..7343389e8ff7 100644 --- a/samples/client/others/typescript-angular-v20/builds/query-param-json/api.base.service.ts +++ b/samples/client/others/typescript-angular-v20/builds/query-param-json/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/others/typescript-angular-v20/builds/query-param-json/api/default.service.ts b/samples/client/others/typescript-angular-v20/builds/query-param-json/api/default.service.ts index d7733df8c4b2..e8d54af9174e 100644 --- a/samples/client/others/typescript-angular-v20/builds/query-param-json/api/default.service.ts +++ b/samples/client/others/typescript-angular-v20/builds/query-param-json/api/default.service.ts @@ -40,14 +40,15 @@ export class DefaultService extends BaseService { /** * @endpoint get /search * @param filter Filter + * @param tags Tags * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. * @param options additional options */ - public search(filter?: Filter, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable; - public search(filter?: Filter, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; - public search(filter?: Filter, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; - public search(filter?: Filter, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable { + public search(filter?: Filter, tags?: Set, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable; + public search(filter?: Filter, tags?: Set, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; + public search(filter?: Filter, tags?: Set, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; + public search(filter?: Filter, tags?: Set, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable { let localVarQueryParameters = new OpenApiHttpParams(this.encoder); @@ -60,6 +61,15 @@ export class DefaultService extends BaseService { ); + localVarQueryParameters = this.addToHttpParams( + localVarQueryParameters, + 'tags', + tags, + QueryParamStyle.Json, + false, + ); + + let localVarHeaders = this.defaultHeaders; const localVarHttpHeaderAcceptSelected: string | undefined = options?.httpHeaderAccept ?? this.configuration.selectHeaderAccept([ diff --git a/samples/client/others/typescript-angular-v20/projects/app/src/api.query_param_json.spec.ts b/samples/client/others/typescript-angular-v20/projects/app/src/api.query_param_json.spec.ts index 35960f072935..8833b3d55364 100644 --- a/samples/client/others/typescript-angular-v20/projects/app/src/api.query_param_json.spec.ts +++ b/samples/client/others/typescript-angular-v20/projects/app/src/api.query_param_json.spec.ts @@ -37,4 +37,13 @@ describe('JSON Query Param testing', () => { const req = httpTesting.expectOne(`http://localhost/search?filter=${filterJsonEncoded}`); expect(req.request.method).toEqual('GET'); }); + + it('should serialize a Set query parameter as a JSON array', () => { + const tags = new Set(['a', 'b']); + const tagsJsonEncoded = encodeURIComponent('["a","b"]'); + + service.search(undefined, tags).subscribe(); + const req = httpTesting.expectOne(`http://localhost/search?tags=${tagsJsonEncoded}`); + expect(req.request.method).toEqual('GET'); + }); }); diff --git a/samples/client/others/typescript-angular/builds/composed-schemas-tagged-unions/api.base.service.ts b/samples/client/others/typescript-angular/builds/composed-schemas-tagged-unions/api.base.service.ts index a3f5732154dc..a82ce3db8a3a 100644 --- a/samples/client/others/typescript-angular/builds/composed-schemas-tagged-unions/api.base.service.ts +++ b/samples/client/others/typescript-angular/builds/composed-schemas-tagged-unions/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/others/typescript-angular/builds/composed-schemas/api.base.service.ts b/samples/client/others/typescript-angular/builds/composed-schemas/api.base.service.ts index a3f5732154dc..a82ce3db8a3a 100644 --- a/samples/client/others/typescript-angular/builds/composed-schemas/api.base.service.ts +++ b/samples/client/others/typescript-angular/builds/composed-schemas/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/petstore/typescript-angular-v18-provided-in-root/builds/default/api.base.service.ts b/samples/client/petstore/typescript-angular-v18-provided-in-root/builds/default/api.base.service.ts index be3fe1db2090..f3a7b34e9b49 100644 --- a/samples/client/petstore/typescript-angular-v18-provided-in-root/builds/default/api.base.service.ts +++ b/samples/client/petstore/typescript-angular-v18-provided-in-root/builds/default/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/petstore/typescript-angular-v19-provided-in-root/builds/default/api.base.service.ts b/samples/client/petstore/typescript-angular-v19-provided-in-root/builds/default/api.base.service.ts index be3fe1db2090..f3a7b34e9b49 100644 --- a/samples/client/petstore/typescript-angular-v19-provided-in-root/builds/default/api.base.service.ts +++ b/samples/client/petstore/typescript-angular-v19-provided-in-root/builds/default/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/petstore/typescript-angular-v19-with-angular-dependency-params/builds/default/api.base.service.ts b/samples/client/petstore/typescript-angular-v19-with-angular-dependency-params/builds/default/api.base.service.ts index be3fe1db2090..f3a7b34e9b49 100644 --- a/samples/client/petstore/typescript-angular-v19-with-angular-dependency-params/builds/default/api.base.service.ts +++ b/samples/client/petstore/typescript-angular-v19-with-angular-dependency-params/builds/default/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/petstore/typescript-angular-v19/builds/default/api.base.service.ts b/samples/client/petstore/typescript-angular-v19/builds/default/api.base.service.ts index be3fe1db2090..f3a7b34e9b49 100644 --- a/samples/client/petstore/typescript-angular-v19/builds/default/api.base.service.ts +++ b/samples/client/petstore/typescript-angular-v19/builds/default/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/petstore/typescript-angular-v20-provided-in-root/builds/default/api.base.service.ts b/samples/client/petstore/typescript-angular-v20-provided-in-root/builds/default/api.base.service.ts index be3fe1db2090..f3a7b34e9b49 100644 --- a/samples/client/petstore/typescript-angular-v20-provided-in-root/builds/default/api.base.service.ts +++ b/samples/client/petstore/typescript-angular-v20-provided-in-root/builds/default/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/petstore/typescript-angular-v20/builds/default/api.base.service.ts b/samples/client/petstore/typescript-angular-v20/builds/default/api.base.service.ts index be3fe1db2090..f3a7b34e9b49 100644 --- a/samples/client/petstore/typescript-angular-v20/builds/default/api.base.service.ts +++ b/samples/client/petstore/typescript-angular-v20/builds/default/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/petstore/typescript-angular-v21-provided-in-root/builds/default/api.base.service.ts b/samples/client/petstore/typescript-angular-v21-provided-in-root/builds/default/api.base.service.ts index be3fe1db2090..f3a7b34e9b49 100644 --- a/samples/client/petstore/typescript-angular-v21-provided-in-root/builds/default/api.base.service.ts +++ b/samples/client/petstore/typescript-angular-v21-provided-in-root/builds/default/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/petstore/typescript-angular-v21/builds/default/api.base.service.ts b/samples/client/petstore/typescript-angular-v21/builds/default/api.base.service.ts index be3fe1db2090..f3a7b34e9b49 100644 --- a/samples/client/petstore/typescript-angular-v21/builds/default/api.base.service.ts +++ b/samples/client/petstore/typescript-angular-v21/builds/default/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/petstore/typescript-angular-v22-provided-in-root/builds/default/api.base.service.ts b/samples/client/petstore/typescript-angular-v22-provided-in-root/builds/default/api.base.service.ts index be3fe1db2090..f3a7b34e9b49 100644 --- a/samples/client/petstore/typescript-angular-v22-provided-in-root/builds/default/api.base.service.ts +++ b/samples/client/petstore/typescript-angular-v22-provided-in-root/builds/default/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/petstore/typescript-angular-v22-provided-in-root/builds/with-http-resource/api.base.service.ts b/samples/client/petstore/typescript-angular-v22-provided-in-root/builds/with-http-resource/api.base.service.ts index f1be6d0471fa..19277d67f38e 100644 --- a/samples/client/petstore/typescript-angular-v22-provided-in-root/builds/with-http-resource/api.base.service.ts +++ b/samples/client/petstore/typescript-angular-v22-provided-in-root/builds/with-http-resource/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited diff --git a/samples/client/petstore/typescript-angular-v22/builds/default/api.base.service.ts b/samples/client/petstore/typescript-angular-v22/builds/default/api.base.service.ts index be3fe1db2090..f3a7b34e9b49 100644 --- a/samples/client/petstore/typescript-angular-v22/builds/default/api.base.service.ts +++ b/samples/client/petstore/typescript-angular-v22/builds/default/api.base.service.ts @@ -53,7 +53,7 @@ export class BaseService { httpParams, ); } else if (paramStyle === QueryParamStyle.Json) { - return httpParams.append(key, JSON.stringify(value)); + return httpParams.append(key, JSON.stringify(value, (_, v) => v instanceof Set ? Array.from(v) : v)); } else { // Form-style, SpaceDelimited or PipeDelimited