Repository: sindresorhus/got
Pull request #622 (2018-09-26 19:50:31)

Include `body` property in `HTTPError`
#### Description

The ability to look at the body of the error response inside the `retries` function .

#### Why?

Some services use the response body to provide an extended description of why the error occurred (for example, reason of [409 code](https://developer.mozilla.org/docs/Web/HTTP/Status/409)).

We would like to use this field for logging.

mrmlnc: Maybe it makes sense to also pass `request` as field of the error?

Patch:
diff --git a/readme.md b/readme.md
index c86dad4..4ca2df9 100644
--- a/readme.md
+++ b/readme.md
@@ -121,7 +121,7 @@ Very useful when used with `got.extend()` to create niche-specific Got instances
 
 Can be a string or a [WHATWG `URL`](https://nodejs.org/api/url.html#url_class_url).
 
-Backslash at the end of `baseUrl` and at the beginning of the `url` argument is optional:
+Slash at the end of `baseUrl` and at the beginning of the `url` argument is optional:
 
 ```js
 await got('hello', {baseUrl: 'https://example.com/v1'});
@@ -541,7 +541,7 @@ Options are deeply merged to a new object. The value of each key is determined a
 
 ## Errors
 
-Each error contains (if available) `statusCode`, `statusMessage`, `host`, `hostname`, `method`, `path`, `protocol` and `url` properties to make debugging easier.
+Each error contains (if available) `body`, `statusCode`, `statusMessage`, `host`, `hostname`, `method`, `path`, `protocol` and `url` properties to make debugging easier.
 
 In Promise mode, the `response` is attached to the error.
 
diff --git a/source/as-promise.js b/source/as-promise.js
index e22c41b..3bcb364 100644
--- a/source/as-promise.js
+++ b/source/as-promise.js
@@ -74,7 +74,7 @@ module.exports = options => {
 			}
 
 			if (statusCode !== 304 && (statusCode < 200 || statusCode > limitStatusCode)) {
-				const error = new HTTPError(statusCode, response.statusMessage, response.headers, options);
+				const error = new HTTPError(response, options);
 				Object.defineProperty(error, 'response', {value: response});
 				emitter.emit('retry', error, retried => {
 					if (!retried) {
diff --git a/source/as-stream.js b/source/as-stream.js
index 38143bb..b8b4f1c 100644
--- a/source/as-stream.js
+++ b/source/as-stream.js
@@ -56,7 +56,7 @@ module.exports = options => {
 		});
 
 		if (options.throwHttpErrors && statusCode !== 304 && (statusCode < 200 || statusCode > 299)) {
-			proxy.emit('error', new HTTPError(statusCode, response.statusMessage, response.headers, options), null, response);
+			proxy.emit('error', new HTTPError(response, options), null, response);
 			return;
 		}
 
diff --git a/source/errors.js b/source/errors.js
index dff0576..dafb39d 100644
--- a/source/errors.js
+++ b/source/errors.js
@@ -59,7 +59,10 @@ module.exports.ParseError = class extends GotError {
 };
 
 module.exports.HTTPError = class extends GotError {
-	constructor(statusCode, statusMessage, headers, opts) {
+	constructor(response, opts) {
+		const {statusCode} = response;
+		let {statusMessage} = response;
+
 		if (statusMessage) {
 			statusMessage = statusMessage.replace(/\r?\n/g, ' ').trim();
 		} else {
@@ -69,7 +72,8 @@ module.exports.HTTPError = class extends GotError {
 		this.name = 'HTTPError';
 		this.statusCode = statusCode;
 		this.statusMessage = statusMessage;
-		this.headers = headers;
+		this.headers = response.headers;
+		this.body = response.body;
 	}
 };
 


Test patch:
diff --git a/test/error.js b/test/error.js
index b320b97..1f36c54 100644
--- a/test/error.js
+++ b/test/error.js
@@ -107,6 +107,12 @@ test('custom status message', async t => {
 	t.is(error.statusMessage, 'Something Exploded');
 });
 
+test('custom body', async t => {
+	const error = await t.throwsAsync(got(s.url));
+	t.is(error.statusCode, 404);
+	t.is(error.body, 'not');
+});
+
 test('no status message is overriden by the default one', async t => {
 	const error = await t.throwsAsync(got(`${s.url}/no-status-message`));
 	t.is(error.statusCode, 400);