Skip to content

Commit 2eea67e

Browse files
Reverier-Xusindresorhus
andauthoredMay 31, 2024··
Add stringifyJson option (#579)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
1 parent 2af72bf commit 2eea67e

File tree

5 files changed

+73
-1
lines changed

5 files changed

+73
-1
lines changed
 

‎readme.md

+25
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,31 @@ const json = await ky('https://example.com', {
428428
}).json();
429429
```
430430

431+
##### stringifyJson
432+
433+
Type: `Function`\
434+
Default: `JSON.stringify()`
435+
436+
User-defined JSON-stringifying function.
437+
438+
Use-cases:
439+
1. Stringify JSON with a custom `replacer` function.
440+
441+
```js
442+
import ky from 'ky';
443+
import {DateTime} from 'luxon';
444+
445+
const json = await ky('https://example.com', {
446+
stringifyJson: data => JSON.stringify(data, (key, value) => {
447+
if (key.endsWith('_at')) {
448+
return DateTime.fromISO(value).toSeconds();
449+
}
450+
451+
return value;
452+
})
453+
}).json();
454+
```
455+
431456
##### fetch
432457

433458
Type: `Function`\

‎source/core/Ky.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ export class Ky {
203203
}
204204

205205
if (this._options.json !== undefined) {
206-
this._options.body = JSON.stringify(this._options.json);
206+
this._options.body = this._options.stringifyJson?.(this._options.json) ?? JSON.stringify(this._options.json);
207207
this.request.headers.set('content-type', this._options.headers.get('content-type') ?? 'application/json');
208208
this.request = new globalThis.Request(this.request, {body: this._options.body});
209209
}

‎source/core/constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export const stop = Symbol('stop');
5050
export const kyOptionKeys: KyOptionsRegistry = {
5151
json: true,
5252
parseJson: true,
53+
stringifyJson: true,
5354
searchParams: true,
5455
prefixUrl: true,
5556
retry: true,

‎source/types/options.ts

+26
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,32 @@ export type KyOptions = {
5858
*/
5959
parseJson?: (text: string) => unknown;
6060

61+
/**
62+
User-defined JSON-stringifying function.
63+
64+
Use-cases:
65+
1. Stringify JSON with a custom `replacer` function.
66+
67+
@default JSON.stringify()
68+
69+
@example
70+
```
71+
import ky from 'ky';
72+
import {DateTime} from 'luxon';
73+
74+
const json = await ky('https://example.com', {
75+
stringifyJson: data => JSON.stringify(data, (key, value) => {
76+
if (key.endsWith('_at')) {
77+
return DateTime.fromISO(value).toSeconds();
78+
}
79+
80+
return value;
81+
})
82+
}).json();
83+
```
84+
*/
85+
stringifyJson?: (data: unknown) => string;
86+
6187
/**
6288
Search parameters to include in the request URL. Setting this will override all existing search parameters in the input URL.
6389

‎test/main.ts

+20
Original file line numberDiff line numberDiff line change
@@ -733,3 +733,23 @@ test('parseJson option with promise.json() shortcut', async t => {
733733

734734
await server.close();
735735
});
736+
737+
test('stringifyJson option with request.json()', async t => {
738+
const server = await createHttpTestServer({bodyParser: false});
739+
740+
const json = {hello: 'world'};
741+
const extra = 'extraValue';
742+
743+
server.post('/', async (request, response) => {
744+
const body = await parseRawBody(request);
745+
t.is(body, JSON.stringify({data: json, extra}));
746+
response.end();
747+
});
748+
749+
await ky.post(server.url, {
750+
stringifyJson: data => JSON.stringify({data, extra}),
751+
json,
752+
});
753+
754+
await server.close();
755+
});

0 commit comments

Comments
 (0)
Please sign in to comment.