Skip to content

Latest commit

 

History

History
299 lines (230 loc) · 6.91 KB

9-hooks.md

File metadata and controls

299 lines (230 loc) · 6.91 KB

> Back to homepage

Hooks API

hooks

Type: object<string, Function[]>

This option represents the hooks to run. Thrown errors will be automatically converted to RequestError.

init

Type: InitHook[]
Default: []

(plainRequestOptions: OptionsInit, options: Options) => void

Called with the plain request options, right before their normalization.
The second argument represents the current Options instance.

Note:

  • This hook must be synchronous.

Note:

  • This is called every time options are merged.

Note:

  • The options object may not have the url property. To modify it, use a beforeRequest hook instead.

Note:

  • This hook is called when a new instance of Options is created.
  • Do not confuse this with the creation of Request or got(…).

Note:

  • When using got(url) or got(url, undefined, defaults) this hook will not be called.

This is especially useful in conjunction with got.extend() when the input needs custom handling.

For example, this can be used to fix typos to migrate from older versions faster.

import got from 'got';

const instance = got.extend({
	hooks: {
		init: [
			plain => {
				if ('followRedirects' in plain) {
					plain.followRedirect = plain.followRedirects;
					delete plain.followRedirects;
				}
			}
		]
	}
});

// Normally, the following would throw:
const response = await instance(
	'https://example.com',
	{
		followRedirects: true
	}
);

// There is no option named `followRedirects`, but we correct it in an `init` hook.

Or you can create your own option and store it in a context:

import got from 'got';

const instance = got.extend({
	hooks: {
		init: [
			(plain, options) => {
				if ('secret' in plain) {
					options.context.secret = plain.secret;
					delete plain.secret;
				}
			}
		],
		beforeRequest: [
			options => {
				options.headers.secret = options.context.secret;
			}
		]
	}
});

const {headers} = await instance(
	'https://httpbin.org/anything',
	{
		secret: 'passphrase'
	}
).json();

console.log(headers.Secret);
//=> 'passphrase'

beforeRequest

Type: BeforeRequestHook[]
Default: []

(options: Options) => Promisable<void | Response | ResponseLike>

Called right before making the request with options.createNativeRequestOptions().
This hook is especially useful in conjunction with got.extend() when you want to sign your request.

Note:

  • Got will make no further changes to the request before it is sent.

Note:

  • Changing options.json or options.form has no effect on the request. You should change options.body instead. If needed, update the options.headers accordingly.
import got from 'got';

const response = await got.post(
	'https://httpbin.org/anything',
	{
		json: {payload: 'old'},
		hooks: {
			beforeRequest: [
				options => {
					options.body = JSON.stringify({payload: 'new'});
					options.headers['content-length'] = options.body.length.toString();
				}
			]
		}
	}
);

Tip:

beforeRedirect

Type: BeforeRedirectHook[]
Default: []

(updatedOptions: Options, plainResponse: PlainResponse) => Promisable<void>

The equivalent of beforeRequest but when redirecting.

Tip:

  • This is especially useful when you want to avoid dead sites.
import got from 'got';

const response = await got('https://example.com', {
	hooks: {
		beforeRedirect: [
			(options, response) => {
				if (options.hostname === 'deadSite') {
					options.hostname = 'fallbackSite';
				}
			}
		]
	}
});

beforeRetry

Type: BeforeRetryHook[]
Default: []

(error: RequestError, retryCount: number) => Promisable<void>

The equivalent of beforeError but when retrying. Additionally, there is a second argument retryCount, the current retry number.

Note:

  • When using the Stream API, this hook is ignored.

Note:

  • When retrying, the beforeRequest hook is called afterwards.

Note:

  • If no retry occurs, the beforeError hook is called instead.

This hook is especially useful when you want to retrieve the cause of a retry.

import got from 'got';

await got('https://httpbin.org/status/500', {
	hooks: {
		beforeRetry: [
			(error, retryCount) => {
				console.log(`Retrying [${retryCount}]: ${error.code}`);
				// Retrying [1]: ERR_NON_2XX_3XX_RESPONSE
			}
		]
	}
});

afterResponse

Type: AfterResponseHook[]
Default: []

(response: Response, retryWithMergedOptions: (options: OptionsInit) => never) => Promisable<Response | CancelableRequest<Response>>

Each function should return the response. This is especially useful when you want to refresh an access token.

Note:

  • When using the Stream API, this hook is ignored.

Note:

  • Calling the retryWithMergedOptions function will trigger beforeRetry hooks. If the retry is successful, all remaining afterResponse hooks will be called. In case of an error, beforeRetry hooks will be called instead. Meanwhile the init, beforeRequest , beforeRedirect as well as already executed afterResponse hooks will be skipped.
import got from 'got';

const instance = got.extend({
	hooks: {
		afterResponse: [
			(response, retryWithMergedOptions) => {
				// Unauthorized
				if (response.statusCode === 401) {
					// Refresh the access token
					const updatedOptions = {
						headers: {
							token: getNewToken()
						}
					};

					// Update the defaults
					instance.defaults.options.merge(updatedOptions);

					// Make a new retry
					return retryWithMergedOptions(updatedOptions);
				}

				// No changes otherwise
				return response;
			}
		],
		beforeRetry: [
			error => {
				// This will be called on `retryWithMergedOptions(...)`
			}
		]
	},
	mutableDefaults: true
});

beforeError

Type: BeforeErrorHook[]
Default: []

(error: RequestError) => Promisable<RequestError>

Called with a RequestError instance. The error is passed to the hook right before it's thrown.

This is especially useful when you want to have more detailed errors.

import got from 'got';

await got('https://api.github.com/repos/sindresorhus/got/commits', {
	responseType: 'json',
	hooks: {
		beforeError: [
			error => {
				const {response} = error;
				if (response && response.body) {
					error.name = 'GitHubError';
					error.message = `${response.body.message} (${response.statusCode})`;
				}

				return error;
			}
		]
	}
});