Repository: sindresorhus/got (ts)

Issue:
Handling both ParseError and HTTPError simultaneously
[Previous discussion](https://github.com/SamVerschueren/travis-got/pull/2#pullrequestreview-25498565) /cc @SamVerschueren @floatdrop @sindresorhus

To summarize, Travis CI’s API returns HTML on `403 Forbidden` responses. For example, try:

```sh
curl -i -H "Authorization: token fail" https://api.travis-ci.org/repos/SamVerschueren/travis-got 
```

When using got’s `json` option this causes a `ParseError` (instead of an `HTTPError`) to be thrown. To avoid this, I suggested to catch the error, check the status code for `403`, and re-throw an `HTTPError`. While this works, it requires us to manually create an error which is an undocumented API of got, as far as I can tell.

@SamVerschueren suggested to disable got’s `json` option and parse the body ourselves. Again, while this works, we would still have to manually throw a `ParseError` in case the body can’t be parsed.

So, either way, we would have to to manually create and throw a `ParseError` or an `HTTPError`.

> I would recommend looking into how other HTTP libs handle this, like `request`. We might be doing something wrong, or not.

@sindresorhus request currently just [logs a debug message](https://github.com/request/request/blob/v2.80.1/request.js#L1116-L1120). This behavior has also been discussed in https://github.com/request/request/issues/440.

Pull request description:
Only throw ParseError on 2xx responses
Resolves #278.

Patch:
diff --git a/index.js b/index.js
index 7691716..41487af 100644
--- a/index.js
+++ b/index.js
@@ -128,7 +128,9 @@ function asPromise(opts) {
 						try {
 							res.body = JSON.parse(res.body);
 						} catch (e) {
-							throw new got.ParseError(e, statusCode, opts, data);
+							if (statusCode >= 200 && statusCode < 300) {
+								throw new got.ParseError(e, statusCode, opts, data);
+							}
 						}
 					}
 
diff --git a/readme.md b/readme.md
index 9d2579c..e5947e7 100644
--- a/readme.md
+++ b/readme.md
@@ -203,7 +203,7 @@ When reading from response stream fails.
 
 #### got.ParseError
 
-When `json` option is enabled and `JSON.parse` fails.
+When `json` option is enabled, server response code is 2xx, and `JSON.parse` fails.
 
 #### got.HTTPError
 


Test patch:
diff --git a/test/json-parse.js b/test/json-parse.js
index 1e2c98b..8d88f88 100644
--- a/test/json-parse.js
+++ b/test/json-parse.js
@@ -66,21 +66,21 @@ test('parses non-200 responses', async t => {
 	}
 });
 
-test('catches errors on invalid non-200 responses', async t => {
+test('ignores errors on invalid non-200 responses', async t => {
 	try {
 		await got(`${s.url}/non200-invalid`, {json: true});
 		t.fail('Exception was not thrown');
 	} catch (err) {
-		t.regex(err.message, /Unexpected token/);
+		t.is(err.message, 'Response code 500 (Internal Server Error)');
 		t.is(err.response.body, 'Internal error');
 		t.is(err.path, '/non200-invalid');
 	}
 });
 
 test('should have statusCode in err', async t => {
-	const err = await t.throws(got(`${s.url}/non200-invalid`, {json: true}));
+	const err = await t.throws(got(`${s.url}/invalid`, {json: true}));
 	t.is(err.constructor, got.ParseError);
-	t.is(err.statusCode, 500);
+	t.is(err.statusCode, 200);
 });
 
 test('should set correct headers', async t => {