Skip to content

Commit c15b19a

Browse files
author
Fransis Young
committed
fix(client-axios): ensures falsy request body can be serialized
ensures request is sent with valid serialized or unserialized data resolves: #2599, related: #2553
1 parent f33bc1d commit c15b19a

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

packages/openapi-ts/src/plugins/@hey-api/client-axios/__tests__/client.test.ts

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import type { AxiosInstance } from 'axios';
12
import axios from 'axios';
2-
import { describe, expect, it } from 'vitest';
3+
import { describe, expect, it, vi } from 'vitest';
34

45
import { createClient } from '../bundle/client';
56

@@ -83,3 +84,87 @@ describe('AxiosInstance', () => {
8384
);
8485
});
8586
});
87+
88+
describe('unserialized request body handling', () => {
89+
const client = createClient({ baseURL: 'https://example.com' });
90+
91+
const scenarios = [
92+
{ body: 0 },
93+
{ body: false },
94+
{ body: 'test string' },
95+
{ body: '' },
96+
];
97+
98+
it.each(scenarios)(
99+
'handles plain text body with $body value',
100+
async ({ body }) => {
101+
const mockAxios = vi.fn();
102+
103+
await client.post({
104+
axios: mockAxios as Partial<AxiosInstance> as AxiosInstance,
105+
body,
106+
bodySerializer: null,
107+
headers: {
108+
'Content-Type': 'text/plain',
109+
},
110+
url: '/test',
111+
});
112+
113+
expect(mockAxios).toHaveBeenCalledWith(
114+
expect.objectContaining({
115+
data: body,
116+
}),
117+
);
118+
},
119+
);
120+
});
121+
122+
describe('serialized request body handling', () => {
123+
const client = createClient({ baseURL: 'https://example.com' });
124+
125+
const scenarios = [
126+
{
127+
body: '',
128+
expectBodyValue: false,
129+
serializedBody: '',
130+
},
131+
{
132+
body: 0,
133+
expectBodyValue: true,
134+
serializedBody: 0,
135+
},
136+
{
137+
body: false,
138+
expectBodyValue: true,
139+
serializedBody: false,
140+
},
141+
{
142+
body: {},
143+
expectBodyValue: true,
144+
serializedBody: '{"key":"value"}',
145+
},
146+
];
147+
148+
it.each(scenarios)(
149+
'handles $serializedBody serializedBody value',
150+
async ({ body, expectBodyValue, serializedBody }) => {
151+
const mockAxios = vi.fn();
152+
153+
await client.post({
154+
axios: mockAxios as Partial<AxiosInstance> as AxiosInstance,
155+
body,
156+
bodySerializer: () => serializedBody,
157+
headers: {
158+
'Content-Type': 'application/json',
159+
},
160+
url: '/test',
161+
});
162+
163+
expect(mockAxios).toHaveBeenCalledWith(
164+
expect.objectContaining({
165+
data: expectBodyValue ? serializedBody : null,
166+
}),
167+
);
168+
},
169+
);
170+
});

packages/openapi-ts/src/plugins/@hey-api/client-axios/bundle/client.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const createClient = (config: Config = {}): Client => {
5757
await opts.requestValidator(opts);
5858
}
5959

60-
if (opts.body && opts.bodySerializer) {
60+
if (opts.body !== undefined && opts.bodySerializer) {
6161
opts.body = opts.bodySerializer(opts.body);
6262
}
6363

@@ -78,7 +78,7 @@ export const createClient = (config: Config = {}): Client => {
7878
const response = await _axios({
7979
...optsWithoutAuth,
8080
baseURL: opts.baseURL as string,
81-
data: opts.body,
81+
data: getValidRequestBody(opts),
8282
headers: opts.headers as RawAxiosRequestHeaders,
8383
// let `paramsSerializer()` handle query params if it exists
8484
params: opts.paramsSerializer ? opts.query : undefined,
@@ -112,6 +112,23 @@ export const createClient = (config: Config = {}): Client => {
112112
}
113113
};
114114

115+
function getValidRequestBody(options: RequestOptions) {
116+
const hasBody = options.body !== undefined;
117+
const isSerializedBody = hasBody && options.bodySerializer;
118+
119+
if (isSerializedBody) {
120+
return options.body !== '' ? options.body : null;
121+
}
122+
123+
// plain/text body
124+
if (hasBody) {
125+
return options.body;
126+
}
127+
128+
// no body was provided
129+
return undefined;
130+
}
131+
115132
const makeMethodFn =
116133
(method: Uppercase<HttpMethod>) => (options: RequestOptions) =>
117134
request({ ...options, method });

0 commit comments

Comments
 (0)