Skip to content

Commit

Permalink
Add parseJson option (#272)
Browse files Browse the repository at this point in the history
* feat: Options.parseJson

fixes #254

* Update index.d.ts

* Update readme.md

* Support parseJson option with response.json()

* docs: remove the limitation clause

* Update index.js

Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
Co-authored-by: Seth Holladay <me@seth-holladay.com>
  • Loading branch information
3 people committed Jul 17, 2020
1 parent 71a8d59 commit 95e7fd7
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 1 deletion.
23 changes: 23 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,29 @@ export interface Options extends Omit<RequestInit, 'headers'> {
*/
json?: unknown;

/**
User-defined JSON-parsing function.
Use-cases:
1. Parse JSON via the [`bourne` package](https://github.com/hapijs/bourne) to protect from prototype pollution.
2. Parse JSON with [`reviver` option of `JSON.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse).
@default JSON.parse()
@example
```
import ky from 'ky';
import bourne from '@hapijs/bourne';
(async () => {
const parsed = await ky('https://example.com', {
parseJson: text => bourne(text)
}).json();
})();
```
*/
parseJson?: (text: string) => unknown

/**
Search parameters to include in the request URL. Setting this will override all existing search parameters in the input URL.
Expand Down
20 changes: 19 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,12 @@ class Ky {
return this._stream(response.clone(), this._options.onDownloadProgress);
}

if (this._options.parseJson) {
response.json = async () => {
return this._options.parseJson(await response.text());
};
}

return response;
};

Expand All @@ -337,8 +343,20 @@ class Ky {
for (const [type, mimeType] of Object.entries(responseTypes)) {
result[type] = async () => {
this.request.headers.set('accept', this.request.headers.get('accept') || mimeType);

const response = (await result).clone();
return (type === 'json' && response.status === 204) ? '' : response[type]();

if (type === 'json') {
if (response.status === 204) {
return '';
}

if (options.parseJson) {
return options.parseJson(await response.text());
}
}

return response[type]();
};
}

Expand Down
22 changes: 22 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,28 @@ import ky from 'ky';
})();
```

##### parseJson

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

User-defined JSON-parsing function.

Use-cases:
1. Parse JSON via the [`bourne` package](https://github.com/hapijs/bourne) to protect from prototype pollution.
2. Parse JSON with [`reviver` option of `JSON.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse).

```js
import ky from 'ky';
import bourne from '@hapijs/bourne';

(async () => {
const parsed = await ky('https://example.com', {
parseJson: text => bourne(text)
}).json();
})();
```

### ky.extend(defaultOptions)

Create a new `ky` instance with some defaults overridden with your own.
Expand Down
47 changes: 47 additions & 0 deletions test/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -585,3 +585,50 @@ test('POST JSON with falsey value', async t => { // #222

await server.close();
});

test('parseJson option with response.json()', async t => {
const json = {hello: 'world'};

const server = await createTestServer();
server.get('/', async (request, response) => {
response.json(json);
});

const response = await ky.get(server.url, {
parseJson: text => ({
...JSON.parse(text),
extra: 'extraValue'
})
});
const responseJson = await response.json();

t.deepEqual(responseJson, {
...json,
extra: 'extraValue'
});

await server.close();
});

test('parseJson option with promise.json() shortcut', async t => {
const json = {hello: 'world'};

const server = await createTestServer();
server.get('/', async (request, response) => {
response.json(json);
});

const responseJson = await ky.get(server.url, {
parseJson: text => ({
...JSON.parse(text),
extra: 'extraValue'
})
}).json();

t.deepEqual(responseJson, {
...json,
extra: 'extraValue'
});

await server.close();
});

0 comments on commit 95e7fd7

Please sign in to comment.