Skip to content

Commit fcce96a

Browse files
authored
Merge pull request #2039 from Le0Developer/fix/empty-query-params
fix(clients): fix query string encoding with empty lists/objects
2 parents f46eb6d + 65d4155 commit fcce96a

File tree

11 files changed

+158
-179
lines changed

11 files changed

+158
-179
lines changed

.changeset/stupid-moles-talk.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@hey-api/client-axios': patch
3+
'@hey-api/client-custom': patch
4+
'@hey-api/client-fetch': patch
5+
'@hey-api/client-next': patch
6+
'@hey-api/client-nuxt': patch
7+
---
8+
9+
fix(clients): fix query string encoding with empty lists/objects

packages/client-axios/src/utils.ts

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export const createQuerySerializer = <T = unknown>({
9494
object,
9595
}: QuerySerializerOptions = {}) => {
9696
const querySerializer = (queryParams: T) => {
97-
let search: string[] = [];
97+
const search: string[] = [];
9898
if (queryParams && typeof queryParams === 'object') {
9999
for (const name in queryParams) {
100100
const value = queryParams[name];
@@ -104,43 +104,33 @@ export const createQuerySerializer = <T = unknown>({
104104
}
105105

106106
if (Array.isArray(value)) {
107-
search = [
108-
...search,
109-
serializeArrayParam({
110-
allowReserved,
111-
explode: true,
112-
name,
113-
style: 'form',
114-
value,
115-
...array,
116-
}),
117-
];
118-
continue;
119-
}
120-
121-
if (typeof value === 'object') {
122-
search = [
123-
...search,
124-
serializeObjectParam({
125-
allowReserved,
126-
explode: true,
127-
name,
128-
style: 'deepObject',
129-
value: value as Record<string, unknown>,
130-
...object,
131-
}),
132-
];
133-
continue;
134-
}
135-
136-
search = [
137-
...search,
138-
serializePrimitiveParam({
107+
const serializedArray = serializeArrayParam({
108+
allowReserved,
109+
explode: true,
110+
name,
111+
style: 'form',
112+
value,
113+
...array,
114+
});
115+
if (serializedArray) search.push(serializedArray);
116+
} else if (typeof value === 'object') {
117+
const serializedObject = serializeObjectParam({
118+
allowReserved,
119+
explode: true,
120+
name,
121+
style: 'deepObject',
122+
value: value as Record<string, unknown>,
123+
...object,
124+
});
125+
if (serializedObject) search.push(serializedObject);
126+
} else {
127+
const serializedPrimitive = serializePrimitiveParam({
139128
allowReserved,
140129
name,
141130
value: value as string,
142-
}),
143-
];
131+
});
132+
if (serializedPrimitive) search.push(serializedPrimitive);
133+
}
144134
}
145135
}
146136
return search.join('&');

packages/client-custom/src/utils.ts

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export const createQuerySerializer = <T = unknown>({
9898
object,
9999
}: QuerySerializerOptions = {}) => {
100100
const querySerializer = (queryParams: T) => {
101-
let search: string[] = [];
101+
const search: string[] = [];
102102
if (queryParams && typeof queryParams === 'object') {
103103
for (const name in queryParams) {
104104
const value = queryParams[name];
@@ -108,43 +108,33 @@ export const createQuerySerializer = <T = unknown>({
108108
}
109109

110110
if (Array.isArray(value)) {
111-
search = [
112-
...search,
113-
serializeArrayParam({
114-
allowReserved,
115-
explode: true,
116-
name,
117-
style: 'form',
118-
value,
119-
...array,
120-
}),
121-
];
122-
continue;
123-
}
124-
125-
if (typeof value === 'object') {
126-
search = [
127-
...search,
128-
serializeObjectParam({
129-
allowReserved,
130-
explode: true,
131-
name,
132-
style: 'deepObject',
133-
value: value as Record<string, unknown>,
134-
...object,
135-
}),
136-
];
137-
continue;
138-
}
139-
140-
search = [
141-
...search,
142-
serializePrimitiveParam({
111+
const serializedArray = serializeArrayParam({
112+
allowReserved,
113+
explode: true,
114+
name,
115+
style: 'form',
116+
value,
117+
...array,
118+
});
119+
if (serializedArray) search.push(serializedArray);
120+
} else if (typeof value === 'object') {
121+
const serializedObject = serializeObjectParam({
122+
allowReserved,
123+
explode: true,
124+
name,
125+
style: 'deepObject',
126+
value: value as Record<string, unknown>,
127+
...object,
128+
});
129+
if (serializedObject) search.push(serializedObject);
130+
} else {
131+
const serializedPrimitive = serializePrimitiveParam({
143132
allowReserved,
144133
name,
145134
value: value as string,
146-
}),
147-
];
135+
});
136+
if (serializedPrimitive) search.push(serializedPrimitive);
137+
}
148138
}
149139
}
150140
return search.join('&');

packages/client-fetch/src/__tests__/client.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,26 @@ describe('buildUrl', () => {
4242
},
4343
url: '/foo/1?bar=baz',
4444
},
45+
{
46+
options: {
47+
query: {
48+
bar: [],
49+
foo: [],
50+
},
51+
url: '/',
52+
},
53+
url: '/',
54+
},
55+
{
56+
options: {
57+
query: {
58+
bar: [],
59+
foo: ['abc', 'def'],
60+
},
61+
url: '/',
62+
},
63+
url: '/?foo=abc&foo=def',
64+
},
4565
];
4666

4767
it.each(scenarios)('returns $url', ({ options, url }) => {

packages/client-fetch/src/utils.ts

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export const createQuerySerializer = <T = unknown>({
9898
object,
9999
}: QuerySerializerOptions = {}) => {
100100
const querySerializer = (queryParams: T) => {
101-
let search: string[] = [];
101+
const search: string[] = [];
102102
if (queryParams && typeof queryParams === 'object') {
103103
for (const name in queryParams) {
104104
const value = queryParams[name];
@@ -108,43 +108,33 @@ export const createQuerySerializer = <T = unknown>({
108108
}
109109

110110
if (Array.isArray(value)) {
111-
search = [
112-
...search,
113-
serializeArrayParam({
114-
allowReserved,
115-
explode: true,
116-
name,
117-
style: 'form',
118-
value,
119-
...array,
120-
}),
121-
];
122-
continue;
123-
}
124-
125-
if (typeof value === 'object') {
126-
search = [
127-
...search,
128-
serializeObjectParam({
129-
allowReserved,
130-
explode: true,
131-
name,
132-
style: 'deepObject',
133-
value: value as Record<string, unknown>,
134-
...object,
135-
}),
136-
];
137-
continue;
138-
}
139-
140-
search = [
141-
...search,
142-
serializePrimitiveParam({
111+
const serializedArray = serializeArrayParam({
112+
allowReserved,
113+
explode: true,
114+
name,
115+
style: 'form',
116+
value,
117+
...array,
118+
});
119+
if (serializedArray) search.push(serializedArray);
120+
} else if (typeof value === 'object') {
121+
const serializedObject = serializeObjectParam({
122+
allowReserved,
123+
explode: true,
124+
name,
125+
style: 'deepObject',
126+
value: value as Record<string, unknown>,
127+
...object,
128+
});
129+
if (serializedObject) search.push(serializedObject);
130+
} else {
131+
const serializedPrimitive = serializePrimitiveParam({
143132
allowReserved,
144133
name,
145134
value: value as string,
146-
}),
147-
];
135+
});
136+
if (serializedPrimitive) search.push(serializedPrimitive);
137+
}
148138
}
149139
}
150140
return search.join('&');

packages/client-next/src/utils.ts

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export const createQuerySerializer = <T = unknown>({
9898
object,
9999
}: QuerySerializerOptions = {}) => {
100100
const querySerializer = (queryParams: T) => {
101-
let search: string[] = [];
101+
const search: string[] = [];
102102
if (queryParams && typeof queryParams === 'object') {
103103
for (const name in queryParams) {
104104
const value = queryParams[name];
@@ -108,43 +108,33 @@ export const createQuerySerializer = <T = unknown>({
108108
}
109109

110110
if (Array.isArray(value)) {
111-
search = [
112-
...search,
113-
serializeArrayParam({
114-
allowReserved,
115-
explode: true,
116-
name,
117-
style: 'form',
118-
value,
119-
...array,
120-
}),
121-
];
122-
continue;
123-
}
124-
125-
if (typeof value === 'object') {
126-
search = [
127-
...search,
128-
serializeObjectParam({
129-
allowReserved,
130-
explode: true,
131-
name,
132-
style: 'deepObject',
133-
value: value as Record<string, unknown>,
134-
...object,
135-
}),
136-
];
137-
continue;
138-
}
139-
140-
search = [
141-
...search,
142-
serializePrimitiveParam({
111+
const serializedArray = serializeArrayParam({
112+
allowReserved,
113+
explode: true,
114+
name,
115+
style: 'form',
116+
value,
117+
...array,
118+
});
119+
if (serializedArray) search.push(serializedArray);
120+
} else if (typeof value === 'object') {
121+
const serializedObject = serializeObjectParam({
122+
allowReserved,
123+
explode: true,
124+
name,
125+
style: 'deepObject',
126+
value: value as Record<string, unknown>,
127+
...object,
128+
});
129+
if (serializedObject) search.push(serializedObject);
130+
} else {
131+
const serializedPrimitive = serializePrimitiveParam({
143132
allowReserved,
144133
name,
145134
value: value as string,
146-
}),
147-
];
135+
});
136+
if (serializedPrimitive) search.push(serializedPrimitive);
137+
}
148138
}
149139
}
150140
return search.join('&');

0 commit comments

Comments
 (0)