diff --git a/README.md b/README.md index e0af350ec7d..5acff95e270 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,21 @@ Basic usage example: } ``` +You can pass an optional dispatcher to `fetch` as: + +```js +import { fetch, Agent } from 'undici' + +const res = await fetch('https://example.com', { + // Mocks are also supported + dispatcher: new Agent({ + keepAliveTimeout: 10, + keepAliveMaxTimeout: 10 + }) +}) +const json = await res.json() +console.log(json) +``` #### `request.body` diff --git a/index-fetch.js b/index-fetch.js index 2937144bbf8..2ee12fc1ef7 100644 --- a/index-fetch.js +++ b/index-fetch.js @@ -4,7 +4,8 @@ const { getGlobalDispatcher } = require('./lib/global') const fetchImpl = require('./lib/fetch') module.exports.fetch = async function fetch (resource) { - return fetchImpl.apply(getGlobalDispatcher(), arguments) + const dispatcher = (arguments[1] && arguments[1].dispatcher) || getGlobalDispatcher() + return fetchImpl.apply(dispatcher, arguments) } module.exports.FormData = require('./lib/fetch/formdata').FormData module.exports.Headers = require('./lib/fetch/headers').Headers diff --git a/index.js b/index.js index a77e40eb9f0..2248619749c 100644 --- a/index.js +++ b/index.js @@ -86,7 +86,7 @@ if (nodeMajor > 16 || (nodeMajor === 16 && nodeMinor >= 5)) { if (!fetchImpl) { fetchImpl = require('./lib/fetch') } - const dispatcher = getGlobalDispatcher() + const dispatcher = (arguments[1] && arguments[1].dispatcher) || getGlobalDispatcher() return fetchImpl.apply(dispatcher, arguments) } module.exports.Headers = require('./lib/fetch/headers').Headers diff --git a/test/fetch/client-fetch.js b/test/fetch/client-fetch.js index 30fa2ce0098..3ccd42c3418 100644 --- a/test/fetch/client-fetch.js +++ b/test/fetch/client-fetch.js @@ -7,6 +7,13 @@ const { createServer } = require('http') const { ReadableStream } = require('stream/web') const { Blob } = require('buffer') const { fetch, Response, Request, FormData, File } = require('../..') +const { Client, setGlobalDispatcher, Agent } = require('../..') +const nodeFetch = require('../../index-fetch') + +setGlobalDispatcher(new Agent({ + keepAliveTimeout: 1, + keepAliveMaxTimeout: 1 +})) test('function signature', (t) => { t.plan(2) @@ -342,3 +349,57 @@ test('invalid url', async (t) => { t.match(e.cause.message, 'invalid') } }) + +test('custom agent', (t) => { + t.plan(2) + + const obj = { asd: true } + const server = createServer((req, res) => { + res.end(JSON.stringify(obj)) + }) + t.teardown(server.close.bind(server)) + + server.listen(0, async () => { + const dispatcher = new Client('http://localhost:' + server.address().port, { + keepAliveTimeout: 1, + keepAliveMaxTimeout: 1 + }) + const oldDispatch = dispatcher.dispatch + dispatcher.dispatch = function (options, handler) { + t.pass('custom dispatcher') + return oldDispatch.call(this, options, handler) + } + t.teardown(server.close.bind(server)) + const body = await fetch(`http://localhost:${server.address().port}`, { + dispatcher + }) + t.strictSame(obj, await body.json()) + }) +}) + +test('custom agent node fetch', (t) => { + t.plan(2) + + const obj = { asd: true } + const server = createServer((req, res) => { + res.end(JSON.stringify(obj)) + }) + t.teardown(server.close.bind(server)) + + server.listen(0, async () => { + const dispatcher = new Client('http://localhost:' + server.address().port, { + keepAliveTimeout: 1, + keepAliveMaxTimeout: 1 + }) + const oldDispatch = dispatcher.dispatch + dispatcher.dispatch = function (options, handler) { + t.pass('custom dispatcher') + return oldDispatch.call(this, options, handler) + } + t.teardown(server.close.bind(server)) + const body = await nodeFetch.fetch(`http://localhost:${server.address().port}`, { + dispatcher + }) + t.strictSame(obj, await body.json()) + }) +}) diff --git a/test/types/fetch.test-d.ts b/test/types/fetch.test-d.ts index 22d9d14c414..bff8e10b861 100644 --- a/test/types/fetch.test-d.ts +++ b/test/types/fetch.test-d.ts @@ -3,6 +3,7 @@ import { Blob } from 'buffer' import { ReadableStream } from 'stream/web' import { expectType, expectError } from 'tsd' import { + Agent, BodyInit, fetch, FormData, @@ -23,6 +24,9 @@ import { const requestInit: RequestInit = {} const responseInit: ResponseInit = { status: 200, statusText: 'OK' } +const requestInit2: RequestInit = { + dispatcher: new Agent() +} declare const request: Request declare const headers: Headers diff --git a/types/fetch.d.ts b/types/fetch.d.ts index 4a23eabc503..356c4f3262f 100644 --- a/types/fetch.d.ts +++ b/types/fetch.d.ts @@ -7,6 +7,8 @@ import { URL, URLSearchParams } from 'url' import { ReadableStream } from 'stream/web' import { FormData } from './formdata' +import Dispatcher = require('./dispatcher') + export type RequestInfo = string | URL | Request export declare function fetch ( @@ -99,6 +101,7 @@ export interface RequestInit { readonly referrer?: string readonly referrerPolicy?: ReferrerPolicy readonly window?: null + readonly dispatcher?: Dispatcher } export type ReferrerPolicy =