Skip to content

Commit 9003243

Browse files
authored
fix(typescript-angular): handle Set in query parameter serialization (#23442)
* fix(typescript-angular): handle Set in query parameter serialization (#23434) * Update sample files
1 parent 01ef44a commit 9003243

File tree

19 files changed

+171
-88
lines changed

19 files changed

+171
-88
lines changed

modules/openapi-generator/src/main/resources/typescript-angular/api.base.service.mustache

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,16 @@ export class BaseService {
5454
return httpParams.append(key, value.toString());
5555
} else if (value instanceof Date) {
5656
return httpParams.append(key, value.toISOString());
57-
} else if (Array.isArray(value)) {
58-
// Otherwise, if it's an array, add each element.
57+
} else if (Array.isArray(value) || value instanceof Set) {
58+
// Otherwise, if it's an array or set, add each element.
59+
const array = Array.isArray(value) ? value : Array.from(value);
5960
if (paramStyle === QueryParamStyle.Form) {
60-
return httpParams.set(key, value, {explode: explode, delimiter: ','});
61+
return httpParams.set(key, array, {explode: explode, delimiter: ','});
6162
} else if (paramStyle === QueryParamStyle.SpaceDelimited) {
62-
return httpParams.set(key, value, {explode: explode, delimiter: ' '});
63+
return httpParams.set(key, array, {explode: explode, delimiter: ' '});
6364
} else {
6465
// PipeDelimited
65-
return httpParams.set(key, value, {explode: explode, delimiter: '|'});
66+
return httpParams.set(key, array, {explode: explode, delimiter: '|'});
6667
}
6768
} else {
6869
// Otherwise, if it's an object, add each field.

modules/openapi-generator/src/test/resources/3_0/query-param-form.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ paths:
3333
required: false
3434
schema:
3535
type: string
36+
- in: query
37+
name: tags
38+
style: form
39+
explode: true
40+
description: Tags
41+
required: false
42+
schema:
43+
type: array
44+
items:
45+
type: string
46+
uniqueItems: true
3647
responses:
3748
'200':
3849
description: Ok
@@ -71,6 +82,17 @@ paths:
7182
required: false
7283
schema:
7384
type: string
85+
- in: query
86+
name: tags
87+
style: form
88+
explode: false
89+
description: Tags
90+
required: false
91+
schema:
92+
type: array
93+
items:
94+
type: string
95+
uniqueItems: true
7496

7597
responses:
7698
'200':

samples/client/others/typescript-angular-v20/builds/query-param-deep-object/api.base.service.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,16 @@ export class BaseService {
6262
return httpParams.append(key, value.toString());
6363
} else if (value instanceof Date) {
6464
return httpParams.append(key, value.toISOString());
65-
} else if (Array.isArray(value)) {
66-
// Otherwise, if it's an array, add each element.
65+
} else if (Array.isArray(value) || value instanceof Set) {
66+
// Otherwise, if it's an array or set, add each element.
67+
const array = Array.isArray(value) ? value : Array.from(value);
6768
if (paramStyle === QueryParamStyle.Form) {
68-
return httpParams.set(key, value, {explode: explode, delimiter: ','});
69+
return httpParams.set(key, array, {explode: explode, delimiter: ','});
6970
} else if (paramStyle === QueryParamStyle.SpaceDelimited) {
70-
return httpParams.set(key, value, {explode: explode, delimiter: ' '});
71+
return httpParams.set(key, array, {explode: explode, delimiter: ' '});
7172
} else {
7273
// PipeDelimited
73-
return httpParams.set(key, value, {explode: explode, delimiter: '|'});
74+
return httpParams.set(key, array, {explode: explode, delimiter: '|'});
7475
}
7576
} else {
7677
// Otherwise, if it's an object, add each field.

samples/client/others/typescript-angular-v20/builds/query-param-form/api.base.service.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,16 @@ export class BaseService {
6262
return httpParams.append(key, value.toString());
6363
} else if (value instanceof Date) {
6464
return httpParams.append(key, value.toISOString());
65-
} else if (Array.isArray(value)) {
66-
// Otherwise, if it's an array, add each element.
65+
} else if (Array.isArray(value) || value instanceof Set) {
66+
// Otherwise, if it's an array or set, add each element.
67+
const array = Array.isArray(value) ? value : Array.from(value);
6768
if (paramStyle === QueryParamStyle.Form) {
68-
return httpParams.set(key, value, {explode: explode, delimiter: ','});
69+
return httpParams.set(key, array, {explode: explode, delimiter: ','});
6970
} else if (paramStyle === QueryParamStyle.SpaceDelimited) {
70-
return httpParams.set(key, value, {explode: explode, delimiter: ' '});
71+
return httpParams.set(key, array, {explode: explode, delimiter: ' '});
7172
} else {
7273
// PipeDelimited
73-
return httpParams.set(key, value, {explode: explode, delimiter: '|'});
74+
return httpParams.set(key, array, {explode: explode, delimiter: '|'});
7475
}
7576
} else {
7677
// Otherwise, if it's an object, add each field.

samples/client/others/typescript-angular-v20/builds/query-param-form/api/default.service.ts

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,15 @@ export class DefaultService extends BaseService {
4242
* @param ids Ids
4343
* @param filter Filter
4444
* @param country Filter
45+
* @param tags Tags
4546
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
4647
* @param reportProgress flag to report request and response progress.
4748
* @param options additional options
4849
*/
49-
public searchExplode(ids?: Array<number>, filter?: Filter, country?: string, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<Response>;
50-
public searchExplode(ids?: Array<number>, filter?: Filter, country?: string, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<HttpResponse<Response>>;
51-
public searchExplode(ids?: Array<number>, filter?: Filter, country?: string, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<HttpEvent<Response>>;
52-
public searchExplode(ids?: Array<number>, filter?: Filter, country?: string, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<any> {
50+
public searchExplode(ids?: Array<number>, filter?: Filter, country?: string, tags?: Set<string>, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<Response>;
51+
public searchExplode(ids?: Array<number>, filter?: Filter, country?: string, tags?: Set<string>, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<HttpResponse<Response>>;
52+
public searchExplode(ids?: Array<number>, filter?: Filter, country?: string, tags?: Set<string>, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<HttpEvent<Response>>;
53+
public searchExplode(ids?: Array<number>, filter?: Filter, country?: string, tags?: Set<string>, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<any> {
5354

5455
let localVarQueryParameters = new OpenApiHttpParams(this.encoder);
5556

@@ -80,6 +81,15 @@ export class DefaultService extends BaseService {
8081
);
8182

8283

84+
localVarQueryParameters = this.addToHttpParams(
85+
localVarQueryParameters,
86+
'tags',
87+
<any>tags,
88+
QueryParamStyle.Form,
89+
true,
90+
);
91+
92+
8393
let localVarHeaders = this.defaultHeaders;
8494

8595
const localVarHttpHeaderAcceptSelected: string | undefined = options?.httpHeaderAccept ?? this.configuration.selectHeaderAccept([
@@ -126,14 +136,15 @@ export class DefaultService extends BaseService {
126136
* @param ids Ids
127137
* @param filter Filter
128138
* @param country Filter
139+
* @param tags Tags
129140
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
130141
* @param reportProgress flag to report request and response progress.
131142
* @param options additional options
132143
*/
133-
public searchNotExplode(ids?: Array<number>, filter?: Filter, country?: string, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<Response>;
134-
public searchNotExplode(ids?: Array<number>, filter?: Filter, country?: string, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<HttpResponse<Response>>;
135-
public searchNotExplode(ids?: Array<number>, filter?: Filter, country?: string, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<HttpEvent<Response>>;
136-
public searchNotExplode(ids?: Array<number>, filter?: Filter, country?: string, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<any> {
144+
public searchNotExplode(ids?: Array<number>, filter?: Filter, country?: string, tags?: Set<string>, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<Response>;
145+
public searchNotExplode(ids?: Array<number>, filter?: Filter, country?: string, tags?: Set<string>, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<HttpResponse<Response>>;
146+
public searchNotExplode(ids?: Array<number>, filter?: Filter, country?: string, tags?: Set<string>, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<HttpEvent<Response>>;
147+
public searchNotExplode(ids?: Array<number>, filter?: Filter, country?: string, tags?: Set<string>, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable<any> {
137148

138149
let localVarQueryParameters = new OpenApiHttpParams(this.encoder);
139150

@@ -164,6 +175,15 @@ export class DefaultService extends BaseService {
164175
);
165176

166177

178+
localVarQueryParameters = this.addToHttpParams(
179+
localVarQueryParameters,
180+
'tags',
181+
<any>tags,
182+
QueryParamStyle.Form,
183+
false,
184+
);
185+
186+
167187
let localVarHeaders = this.defaultHeaders;
168188

169189
const localVarHttpHeaderAcceptSelected: string | undefined = options?.httpHeaderAccept ?? this.configuration.selectHeaderAccept([

samples/client/others/typescript-angular-v20/builds/query-param-json/api.base.service.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,16 @@ export class BaseService {
6262
return httpParams.append(key, value.toString());
6363
} else if (value instanceof Date) {
6464
return httpParams.append(key, value.toISOString());
65-
} else if (Array.isArray(value)) {
66-
// Otherwise, if it's an array, add each element.
65+
} else if (Array.isArray(value) || value instanceof Set) {
66+
// Otherwise, if it's an array or set, add each element.
67+
const array = Array.isArray(value) ? value : Array.from(value);
6768
if (paramStyle === QueryParamStyle.Form) {
68-
return httpParams.set(key, value, {explode: explode, delimiter: ','});
69+
return httpParams.set(key, array, {explode: explode, delimiter: ','});
6970
} else if (paramStyle === QueryParamStyle.SpaceDelimited) {
70-
return httpParams.set(key, value, {explode: explode, delimiter: ' '});
71+
return httpParams.set(key, array, {explode: explode, delimiter: ' '});
7172
} else {
7273
// PipeDelimited
73-
return httpParams.set(key, value, {explode: explode, delimiter: '|'});
74+
return httpParams.set(key, array, {explode: explode, delimiter: '|'});
7475
}
7576
} else {
7677
// Otherwise, if it's an object, add each field.

samples/client/others/typescript-angular-v20/projects/app/src/api.query_param_form.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const ids: number[] = [4, 5];
88
const filter: Filter = {name: 'John', age: 37, nicknames: ['Joe', 'Joey']};
99
const filterWithSpecialCharacters: Filter = {name: 'Éléonore &,|+', age: 42, nicknames: ['Elé', 'Ellie']};
1010
const country: string = "Belgium";
11+
const tags: Set<string> = new Set(['a', 'b']);
1112

1213
describe('Form Query Param testing', () => {
1314
let httpTesting: HttpTestingController;
@@ -80,6 +81,18 @@ describe('Form Query Param testing', () => {
8081
expect(req.request.method).toEqual('GET');
8182
});
8283

84+
it('should separate the query parameter with ampersands (set only)', async () => {
85+
service.searchExplode(undefined, undefined, undefined, tags).subscribe();
86+
const req = httpTesting.expectOne('http://localhost/search_explode?tags=a&tags=b');
87+
expect(req.request.method).toEqual('GET');
88+
});
89+
90+
it('should separate the query parameter with ampersands (all set including tags)', async () => {
91+
service.searchExplode(ids, filter, country, tags).subscribe();
92+
const req = httpTesting.expectOne('http://localhost/search_explode?ids=4&ids=5&name=John&age=37&nicknames=Joe&nicknames=Joey&country=Belgium&tags=a&tags=b');
93+
expect(req.request.method).toEqual('GET');
94+
});
95+
8396
it('should separate the query parameter with comma (all set)', async () => {
8497
service.searchNotExplode(ids, filter, country).subscribe();
8598
const req = httpTesting.expectOne('http://localhost/search_not_explode?ids=4,5&filter=name,John,age,37,nicknames,Joe,Joey&country=Belgium');
@@ -126,4 +139,16 @@ describe('Form Query Param testing', () => {
126139
expect(req.request.method).toEqual('GET');
127140
});
128141

142+
it('should separate the query parameter with comma (set only)', async () => {
143+
service.searchNotExplode(undefined, undefined, undefined, tags).subscribe();
144+
const req = httpTesting.expectOne('http://localhost/search_not_explode?tags=a,b');
145+
expect(req.request.method).toEqual('GET');
146+
});
147+
148+
it('should separate the query parameter with comma (all set including tags)', async () => {
149+
service.searchNotExplode(ids, filter, country, tags).subscribe();
150+
const req = httpTesting.expectOne('http://localhost/search_not_explode?ids=4,5&filter=name,John,age,37,nicknames,Joe,Joey&country=Belgium&tags=a,b');
151+
expect(req.request.method).toEqual('GET');
152+
});
153+
129154
});

samples/client/others/typescript-angular/builds/composed-schemas-tagged-unions/api.base.service.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,16 @@ export class BaseService {
6262
return httpParams.append(key, value.toString());
6363
} else if (value instanceof Date) {
6464
return httpParams.append(key, value.toISOString());
65-
} else if (Array.isArray(value)) {
66-
// Otherwise, if it's an array, add each element.
65+
} else if (Array.isArray(value) || value instanceof Set) {
66+
// Otherwise, if it's an array or set, add each element.
67+
const array = Array.isArray(value) ? value : Array.from(value);
6768
if (paramStyle === QueryParamStyle.Form) {
68-
return httpParams.set(key, value, {explode: explode, delimiter: ','});
69+
return httpParams.set(key, array, {explode: explode, delimiter: ','});
6970
} else if (paramStyle === QueryParamStyle.SpaceDelimited) {
70-
return httpParams.set(key, value, {explode: explode, delimiter: ' '});
71+
return httpParams.set(key, array, {explode: explode, delimiter: ' '});
7172
} else {
7273
// PipeDelimited
73-
return httpParams.set(key, value, {explode: explode, delimiter: '|'});
74+
return httpParams.set(key, array, {explode: explode, delimiter: '|'});
7475
}
7576
} else {
7677
// Otherwise, if it's an object, add each field.

samples/client/others/typescript-angular/builds/composed-schemas/api.base.service.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,16 @@ export class BaseService {
6262
return httpParams.append(key, value.toString());
6363
} else if (value instanceof Date) {
6464
return httpParams.append(key, value.toISOString());
65-
} else if (Array.isArray(value)) {
66-
// Otherwise, if it's an array, add each element.
65+
} else if (Array.isArray(value) || value instanceof Set) {
66+
// Otherwise, if it's an array or set, add each element.
67+
const array = Array.isArray(value) ? value : Array.from(value);
6768
if (paramStyle === QueryParamStyle.Form) {
68-
return httpParams.set(key, value, {explode: explode, delimiter: ','});
69+
return httpParams.set(key, array, {explode: explode, delimiter: ','});
6970
} else if (paramStyle === QueryParamStyle.SpaceDelimited) {
70-
return httpParams.set(key, value, {explode: explode, delimiter: ' '});
71+
return httpParams.set(key, array, {explode: explode, delimiter: ' '});
7172
} else {
7273
// PipeDelimited
73-
return httpParams.set(key, value, {explode: explode, delimiter: '|'});
74+
return httpParams.set(key, array, {explode: explode, delimiter: '|'});
7475
}
7576
} else {
7677
// Otherwise, if it's an object, add each field.

samples/client/petstore/typescript-angular-v16-provided-in-root/builds/default/api.base.service.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,16 @@ export class BaseService {
6262
return httpParams.append(key, value.toString());
6363
} else if (value instanceof Date) {
6464
return httpParams.append(key, value.toISOString());
65-
} else if (Array.isArray(value)) {
66-
// Otherwise, if it's an array, add each element.
65+
} else if (Array.isArray(value) || value instanceof Set) {
66+
// Otherwise, if it's an array or set, add each element.
67+
const array = Array.isArray(value) ? value : Array.from(value);
6768
if (paramStyle === QueryParamStyle.Form) {
68-
return httpParams.set(key, value, {explode: explode, delimiter: ','});
69+
return httpParams.set(key, array, {explode: explode, delimiter: ','});
6970
} else if (paramStyle === QueryParamStyle.SpaceDelimited) {
70-
return httpParams.set(key, value, {explode: explode, delimiter: ' '});
71+
return httpParams.set(key, array, {explode: explode, delimiter: ' '});
7172
} else {
7273
// PipeDelimited
73-
return httpParams.set(key, value, {explode: explode, delimiter: '|'});
74+
return httpParams.set(key, array, {explode: explode, delimiter: '|'});
7475
}
7576
} else {
7677
// Otherwise, if it's an object, add each field.

0 commit comments

Comments
 (0)