Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for stringifyJson #579

Merged
merged 11 commits into from
May 31, 2024
25 changes: 25 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,31 @@ const json = await ky('https://example.com', {
}).json();
```

##### stringifyJson

Type: `Function`\
Default: `JSON.stringify()`

User-defined JSON-stringifying function.

Use-cases:
1. Stringify JSON with the custom `replacer` function.

```js
import ky from 'ky';
import {DateTime} from 'luxon';

const json = await ky('https://example.com', {
stringifyJson: data => JSON.stringify(data, (key, value) => {
if (key.endsWith('_at')) {
return DateTime.fromISO(value).toSeconds();
}

return value;
})
}).json();
```

##### fetch

Type: `Function`\
Expand Down
2 changes: 1 addition & 1 deletion source/core/Ky.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export class Ky {
}

if (this._options.json !== undefined) {
this._options.body = JSON.stringify(this._options.json);
this._options.body = this._options.stringifyJson?.(this._options.json) ?? JSON.stringify(this._options.json);
this.request.headers.set('content-type', this._options.headers.get('content-type') ?? 'application/json');
this.request = new globalThis.Request(this.request, {body: this._options.body});
}
Expand Down
1 change: 1 addition & 0 deletions source/core/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const stop = Symbol('stop');
export const kyOptionKeys: KyOptionsRegistry = {
json: true,
parseJson: true,
stringifyJson: true,
searchParams: true,
prefixUrl: true,
retry: true,
Expand Down
26 changes: 26 additions & 0 deletions source/types/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,32 @@ export type KyOptions = {
*/
parseJson?: (text: string) => unknown;

/**
User-defined JSON-stringifying function.

Use-cases:
1. Stringify JSON with the custom `replacer` function.

@default JSON.stringify()

@example
```
import ky from 'ky';
import {DateTime} from 'luxon';

const json = await ky('https://example.com', {
stringifyJson: data => JSON.stringify(data, (key, value) => {
if (key.endsWith('_at')) {
return DateTime.fromISO(value).toSeconds();
}

return value;
})
}).json();
```
*/
stringifyJson?: (data: unknown) => string;

/**
Search parameters to include in the request URL. Setting this will override all existing search parameters in the input URL.

Expand Down
23 changes: 23 additions & 0 deletions test/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -733,3 +733,26 @@ test('parseJson option with promise.json() shortcut', async t => {

await server.close();
});

test('stringifyJson option with request.json()', async t => {
const server = await createHttpTestServer({bodyParser: false});

const json = {hello: 'world'};
const result = {data: json, extra: 'extraValue'};

server.post('/', async (request, response) => {
const body = await parseRawBody(request);
t.is(body, JSON.stringify(result));
response.end();
});

await ky.post(server.url, {
stringifyJson: data => JSON.stringify({
data,
extra: 'extraValue',
}),
sindresorhus marked this conversation as resolved.
Show resolved Hide resolved
Reverier-Xu marked this conversation as resolved.
Show resolved Hide resolved
json,
});

await server.close();
});