Skip to content

Commit

Permalink
feat(extend): support function options
Browse files Browse the repository at this point in the history
callback function receives parent's default options to allow extended instance to refer to modify parent options

Closes #586
  • Loading branch information
mfulton26 committed Jul 16, 2024
1 parent 4886b66 commit 184bf19
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 2 deletions.
16 changes: 16 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,22 @@ console.log('unicorn' in response);
//=> true
```

You can also refer to parent defaults by providing a function to `.extend()`.

```js
import ky from 'ky';

const api = ky.create({prefixUrl: 'https://example.com/api'});

const usersApi = api.extend((options) => ({prefixUrl: `${options.prefixUrl}/users`}));

const response = await usersApi.get('123');
//=> 'https://example.com/api/users/123'

const response = await api.get('version');
//=> 'https://example.com/api/version'
```

### ky.create(defaultOptions)

Create a new Ky instance with complete new defaults.
Expand Down
9 changes: 8 additions & 1 deletion source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ const createInstance = (defaults?: Partial<Options>): KyInstance => {
}

ky.create = (newDefaults?: Partial<Options>) => createInstance(validateAndMerge(newDefaults));
ky.extend = (newDefaults?: Partial<Options>) => createInstance(validateAndMerge(defaults, newDefaults));
ky.extend = (newDefaults?: Partial<Options> | ((parentDefaults: Partial<Options>) => Partial<Options>)) => {
if (typeof newDefaults === 'function') {
newDefaults = newDefaults(defaults ?? {});
}

return createInstance(validateAndMerge(defaults, newDefaults));
};

ky.stop = stop;

return ky as KyInstance;
Expand Down
2 changes: 1 addition & 1 deletion source/types/ky.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export type KyInstance = {
@returns A new Ky instance.
*/
extend: (defaultOptions: Options) => KyInstance;
extend: (defaultOptions: Options | ((parentOptions: Options) => Options)) => KyInstance;

/**
A `Symbol` that can be returned by a `beforeRetry` hook to stop the retry. This will also short circuit the remaining `beforeRetry` hooks.
Expand Down
25 changes: 25 additions & 0 deletions test/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,31 @@ test('ky.extend()', async t => {
await server.close();
});

test('ky.extend() with function', async t => {
const server = await createHttpTestServer();
server.get('*', (request, response) => {
response.end(request.url);
});

const api = ky.create({prefixUrl: `${server.url}/api`});
const usersApi = api.extend(options => ({prefixUrl: `${options.prefixUrl!.toString()}/users`}));

t.is(await usersApi.get('123').text(), '/api/users/123');
t.is(await api.get('version').text(), '/api/version');

{
const {ok} = await api.head(server.url);
t.true(ok);
}

{
const {ok} = await usersApi.head(server.url);
t.true(ok);
}

await server.close();
});

test('throws DOMException/Error with name AbortError when aborted by user', async t => {
const server = await createHttpTestServer();
// eslint-disable-next-line @typescript-eslint/no-empty-function
Expand Down

0 comments on commit 184bf19

Please sign in to comment.