Skip to content

Commit

Permalink
Add beforeError hook (#696)
Browse files Browse the repository at this point in the history
  • Loading branch information
szmarczak authored and sindresorhus committed Jan 14, 2019
1 parent 677d0a4 commit 29ffb44
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 9 deletions.
1 change: 1 addition & 0 deletions advanced-creation.md
Expand Up @@ -98,6 +98,7 @@ const defaults = {
'user-agent': `${pkg.name}/${pkg.version} (https://github.com/sindresorhus/got)`
},
hooks: {
beforeError: [],
init: [],
beforeRequest: [],
beforeRedirect: [],
Expand Down
29 changes: 29 additions & 0 deletions readme.md
Expand Up @@ -458,6 +458,35 @@ const instance = got.extend({
});
```

###### hooks.beforeError

Type: `Function[]`<br>
Default: `[]`

Called with an `Error` 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.

**Note**: Errors thrown while normalizing input options are thrown directly and not part of this hook.

```js
const got = require('got');

got('api.github.com/some-endpoint', {
hooks: {
onError: [
error => {
const {response} = error;
if (response && response.body) {
error.name = 'GitHubError';
error.message = `${response.body.message} (${error.statusCode})`;
}

return error;
}
]
}
});
```

#### Response

The response object will typically be a [Node.js HTTP response stream](https://nodejs.org/api/http.html#http_class_http_incomingmessage), however, if returned from the cache it will be a [response-like object](https://github.com/lukechilds/responselike) which behaves in the same way.
Expand Down
1 change: 1 addition & 0 deletions source/known-hook-events.js
@@ -1,6 +1,7 @@
'use strict';

module.exports = [
'beforeError',
'init',
'beforeRequest',
'beforeRedirect',
Expand Down
31 changes: 22 additions & 9 deletions source/request-as-event-emitter.js
Expand Up @@ -33,6 +33,19 @@ module.exports = (options, input) => {
const getCookieString = options.cookieJar ? util.promisify(options.cookieJar.getCookieString.bind(options.cookieJar)) : null;
const agents = is.object(options.agent) ? options.agent : null;

const emitError = async error => {
try {
for (const hook of options.hooks.beforeError) {
// eslint-disable-next-line no-await-in-loop
error = await hook(error);
}

emitter.emit('error', error);
} catch (error2) {
emitter.emit('error', error2);
}
};

const get = async options => {
const currentUrl = redirectString || requestUrl;

Expand Down Expand Up @@ -141,7 +154,7 @@ module.exports = (options, input) => {

getResponse(response, options, emitter);
} catch (error) {
emitter.emit('error', error);
emitError(error);
}
};

Expand All @@ -166,7 +179,7 @@ module.exports = (options, input) => {
}

if (emitter.retry(error) === false) {
emitter.emit('error', error);
emitError(error);
}
});

Expand Down Expand Up @@ -198,7 +211,7 @@ module.exports = (options, input) => {
request.end(uploadComplete);
}
} catch (error) {
emitter.emit('error', new RequestError(error, options));
emitError(new RequestError(error, options));
}
};

Expand All @@ -208,9 +221,9 @@ module.exports = (options, input) => {

cacheRequest.once('error', error => {
if (error instanceof CacheableRequest.RequestError) {
emitter.emit('error', new RequestError(error, options));
emitError(new RequestError(error, options));
} else {
emitter.emit('error', new CacheError(error, options));
emitError(new CacheError(error, options));
}
});

Expand All @@ -220,7 +233,7 @@ module.exports = (options, input) => {
try {
handleRequest(fn.request(options, handleResponse));
} catch (error) {
emitter.emit('error', new RequestError(error, options));
emitError(new RequestError(error, options));
}
}
};
Expand All @@ -231,7 +244,7 @@ module.exports = (options, input) => {
try {
backoff = options.retry.retries(++retryCount, error);
} catch (error2) {
emitter.emit('error', error2);
emitError(error2);
return;
}

Expand All @@ -245,7 +258,7 @@ module.exports = (options, input) => {

await get(options);
} catch (error) {
emitter.emit('error', error);
emitError(error);
}
};

Expand Down Expand Up @@ -291,7 +304,7 @@ module.exports = (options, input) => {

await get(options);
} catch (error) {
emitter.emit('error', error);
emitError(error);
}
});

Expand Down
38 changes: 38 additions & 0 deletions test/hooks.js
Expand Up @@ -169,6 +169,15 @@ test('catches afterResponse promise rejections', async t => {
}), errorString);
});

test('catches beforeError errors', async t => {
await t.throwsAsync(() => got(s.url, {
request: () => {},
hooks: {
beforeError: [() => Promise.reject(error)]
}
}), errorString);
});

test('init is called with options', async t => {
await got(s.url, {
json: true,
Expand Down Expand Up @@ -399,3 +408,32 @@ test.serial('doesn\'t throw on afterResponse retry HTTP failure if throwHttpErro
});
t.is(statusCode, 500);
});

test('beforeError is called with an error', async t => {
await t.throwsAsync(() => got(s.url, {
request: () => {
throw error;
},
hooks: {
beforeError: [error2 => {
t.true(error2 instanceof Error);
return error2;
}]
}
}), errorString);
});

test('beforeError allows modifications', async t => {
const errorString2 = 'foobar';

await t.throwsAsync(() => got(s.url, {
request: () => {
throw error;
},
hooks: {
beforeError: [() => {
return new Error(errorString2);
}]
}
}), errorString2);
});

0 comments on commit 29ffb44

Please sign in to comment.