# Variable: customFetch

[💗 Help the project](https://github.com/sponsors/panva)

Support from the community to continue maintaining and improving this module is welcome. If you find the module useful, please consider supporting the project by [becoming a sponsor](https://github.com/sponsors/panva).

***

• `const` **customFetch**: unique `symbol`

Overrides the Fetch API implementation used for outbound HTTP requests.

When configured on an interface that extends [HttpRequestOptions](../interfaces/HttpRequestOptions.md), this applies to the
`options` parameter for functions that may trigger HTTP requests and replaces the use of global
`fetch`. As a fetch replacement, the arguments and expected return are the same as `fetch`.

In theory any module that claims to be compatible with the Fetch API can be used but your mileage
may vary. No workarounds to allow use of non-conform [Response](https://developer.mozilla.org/docs/Web/API/Response)s will be considered.

If you only need to update the [Request](https://developer.mozilla.org/docs/Web/API/Request) properties you do not need to use a Fetch API
module, just change what you need and pass it to globalThis.fetch just like this module would
normally do.

Its intended use cases are:

- [Request](https://developer.mozilla.org/docs/Web/API/Request)/[Response](https://developer.mozilla.org/docs/Web/API/Response) tracing and logging
- Custom caching strategies for responses of Authorization Server Metadata and JSON Web Key Set
  (JWKS) endpoints
- Changing the [Request](https://developer.mozilla.org/docs/Web/API/Request) properties like headers, body, credentials, mode before it is passed
  to fetch

Known caveats:

- Expect Type-related issues when passing the inputs through to fetch-like modules, they hardly
  ever get their typings inline with actual fetch, you should `@ts-expect-error` them.

## Examples

Using [sindresorhus/ky](https://github.com/sindresorhus/ky) for retries and its hooks feature for
logging outgoing requests and their responses.

```js
import ky from 'ky'

// example use
await oauth.discoveryRequest(new URL('https://as.example.com'), {
  [oauth.customFetch]: (...args) =>
    ky(args[0], {
      ...args[1],
      hooks: {
        beforeRequest: [
          (request) => {
            logRequest(request)
          },
        ],
        beforeRetry: [
          ({ request, error, retryCount }) => {
            logRetry(request, error, retryCount)
          },
        ],
        afterResponse: [
          (request, _, response) => {
            logResponse(request, response)
          },
        ],
      },
    }),
})
```

Using [nodejs/undici](https://github.com/nodejs/undici) to detect and use HTTP proxies.

```ts
import * as undici from 'undici'

// see https://undici.nodejs.org/#/docs/api/EnvHttpProxyAgent
let envHttpProxyAgent = new undici.EnvHttpProxyAgent()

// example use
await oauth.discoveryRequest(new URL('https://as.example.com'), {
  // @ts-ignore
  [oauth.customFetch](...args) {
    return undici.fetch(args[0], { ...args[1], dispatcher: envHttpProxyAgent }) // prettier-ignore
  },
})
```

Using [nodejs/undici](https://github.com/nodejs/undici) to automatically retry network errors.

```ts
import * as undici from 'undici'

// see https://undici.nodejs.org/#/docs/api/RetryAgent
let retryAgent = new undici.RetryAgent(new undici.Agent(), {
  statusCodes: [],
  errorCodes: [
    'ECONNRESET',
    'ECONNREFUSED',
    'ENOTFOUND',
    'ENETDOWN',
    'ENETUNREACH',
    'EHOSTDOWN',
    'UND_ERR_SOCKET',
  ],
})

// example use
await oauth.discoveryRequest(new URL('https://as.example.com'), {
  // @ts-ignore
  [oauth.customFetch](...args) {
    return undici.fetch(args[0], { ...args[1], dispatcher: retryAgent }) // prettier-ignore
  },
})
```

Using [nodejs/undici](https://github.com/nodejs/undici) to mock responses in tests.

```ts
import * as undici from 'undici'

// see https://undici.nodejs.org/#/docs/api/MockAgent
let mockAgent = new undici.MockAgent()
mockAgent.disableNetConnect()

// example use
await oauth.discoveryRequest(new URL('https://as.example.com'), {
  // @ts-ignore
  [oauth.customFetch](...args) {
    return undici.fetch(args[0], { ...args[1], dispatcher: mockAgent }) // prettier-ignore
  },
})
```
