Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTPError code set to 'HTTPError' #1711 #1739

Merged
merged 5 commits into from Jun 17, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 11 additions & 10 deletions readme.md
Expand Up @@ -1705,43 +1705,44 @@ Additionaly, the errors may have `request` (Got Stream) and `response` (Got Resp
#### got.RequestError
When a request fails. Contains a `code` property with error class code, like `ECONNREFUSED`. All the errors below inherit this one.
When a request fails. Contains a `code` property with error class code, like `ECONNREFUSED`. If there is no specific code supplied `code` defaults to `ERR_GEN_REQ_ERROR` All the errors below inherit this one.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that ERR_GOT_REQUEST_ERROR would suit this a bit better. Wdyt?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it. I didn't really love using 'general' error and this is more verbose.

Drewfergusson marked this conversation as resolved.
Show resolved Hide resolved
#### got.CacheError
When a cache method fails, for example, if the database goes down or there's a filesystem error.
When a cache method fails, for example, if the database goes down or there's a filesystem error. Contains a `code` property with `ERR_CACHE_ACCESS` or a more specific failure code.
#### got.ReadError
When reading from response stream fails.
When reading from response stream fails. Contains a `code` property with `ERR_READING_RESPONSE_STREAM` or a more specific failure code.
#### got.ParseError
When server response code is 2xx, and parsing body fails. Includes a `response` property.
When server response code is 2xx, and parsing body fails. Includes a `response` property. Contains a `code` property with `ERR_BODY_PARSE_FAILURE` or a more specific failure code.
#### got.UploadError
When the request body is a stream and an error occurs while reading from that stream.
When the request body is a stream and an error occurs while reading from that stream. Contains a `code` property with `ERR_UPLOAD` or a more specific failure code.
#### got.HTTPError
When the server response code is not 2xx nor 3xx if `options.followRedirect` is `true`, but always except for 304. Includes a `response` property.
When the server response code is not 2xx nor 3xx if `options.followRedirect` is `true`, but always except for 304. Includes a `response` property. Contains a `code` property with `ERR_NON_2XX_3XX_RESPONSE` or a more specific failure code.
#### got.MaxRedirectsError
When the server redirects you more than ten times. Includes a `response` property.
When the server redirects you more than ten times. Includes a `response` property. Contains a `code` property with `ERR_MAX_REDIRECTS`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about ERR_TOO_MANY_REDIRECTS?

#### got.UnsupportedProtocolError
When given an unsupported protocol.
When given an unsupported protocol. Contains a `code` property with `ERR_UNSUPPORTED_PROTOCOL`.
#### got.TimeoutError
When the request is aborted due to a [timeout](#timeout). Includes an `event` and `timings` property.
When the request is aborted due to a [timeout](#timeout). Includes an `event` and `timings` property. Contains a `code` property with `ETIMEDOUT`.
#### got.CancelError
When the request is aborted with `.cancel()`.
When the request is aborted with `.cancel()`. Contains a `code` property with `ERR_CANCELED`.
## Aborting the request
Expand Down
2 changes: 2 additions & 0 deletions source/as-promise/types.ts
Expand Up @@ -267,6 +267,7 @@ export class ParseError extends RequestError {

super(`${error.message} in "${options.url.toString()}"`, error, response.request);
this.name = 'ParseError';
this.code = this.code === 'ERR_GEN_REQ_ERROR' ? 'ERR_BODY_PARSE_FAILURE' : this.code;
}
}

Expand All @@ -279,6 +280,7 @@ export class CancelError extends RequestError {
constructor(request: Request) {
super('Promise was canceled', {}, request);
this.name = 'CancelError';
this.code = 'ERR_CANCELED';
}

get isCanceled() {
Expand Down
8 changes: 7 additions & 1 deletion source/core/index.ts
Expand Up @@ -1191,7 +1191,7 @@ export class RequestError extends Error {
Error.captureStackTrace(this, this.constructor);

this.name = 'RequestError';
this.code = error.code;
this.code = error.code ?? 'ERR_GEN_REQ_ERROR';

if (self instanceof Request) {
Object.defineProperty(this, 'request', {
Expand Down Expand Up @@ -1249,6 +1249,7 @@ export class MaxRedirectsError extends RequestError {
constructor(request: Request) {
super(`Redirected ${request.options.maxRedirects} times. Aborting.`, {}, request);
this.name = 'MaxRedirectsError';
this.code = 'ERR_MAX_REDIRECTS';
}
}

Expand All @@ -1264,6 +1265,7 @@ export class HTTPError extends RequestError {
constructor(response: Response) {
super(`Response code ${response.statusCode} (${response.statusMessage!})`, {}, response.request);
this.name = 'HTTPError';
this.code = 'ERR_NON_2XX_3XX_RESPONSE';
}
}
/**
Expand All @@ -1276,6 +1278,7 @@ export class CacheError extends RequestError {
constructor(error: Error, request: Request) {
super(error.message, error, request);
this.name = 'CacheError';
this.code = this.code === 'ERR_GEN_REQ_ERROR' ? 'ERR_CACHE_ACCESS' : this.code;
}
}

Expand All @@ -1288,6 +1291,7 @@ export class UploadError extends RequestError {
constructor(error: Error, request: Request) {
super(error.message, error, request);
this.name = 'UploadError';
this.code = this.code === 'ERR_GEN_REQ_ERROR' ? 'ERR_UPLOAD' : this.code;
}
}

Expand Down Expand Up @@ -1319,6 +1323,7 @@ export class ReadError extends RequestError {
constructor(error: Error, request: Request) {
super(error.message, error, request);
this.name = 'ReadError';
this.code = this.code === 'ERR_GEN_REQ_ERROR' ? 'ERR_READING_RESPONSE_STREAM' : this.code;
}
}

Expand All @@ -1329,6 +1334,7 @@ export class UnsupportedProtocolError extends RequestError {
constructor(options: NormalizedOptions) {
super(`Unsupported protocol "${options.url.protocol}"`, {}, options);
this.name = 'UnsupportedProtocolError';
this.code = 'ERR_UNSUPPORTED_PROTOCOL';
}
}

Expand Down
5 changes: 4 additions & 1 deletion test/cache.ts
Expand Up @@ -120,7 +120,10 @@ test('cache error throws `got.CacheError`', withServer, async (t, server, got) =
const cache = {};

// @ts-expect-error Error tests
await t.throwsAsync(got({cache}), {instanceOf: got.CacheError});
await t.throwsAsync(got({cache}), {
instanceOf: got.CacheError,
code: 'ERR_CACHE_ACCESS'
});
});

test('doesn\'t cache response when received HTTP error', withServer, async (t, server, got) => {
Expand Down
35 changes: 28 additions & 7 deletions test/cancel.ts
Expand Up @@ -79,7 +79,10 @@ test.serial('does not retry after cancelation', withServerAndFakeTimers, async (
gotPromise.cancel();
});

await t.throwsAsync(gotPromise, {instanceOf: CancelError});
await t.throwsAsync(gotPromise, {
instanceOf: CancelError,
code: 'ERR_CANCELED'
});
await t.notThrowsAsync(promise, 'Request finished instead of aborting.');
});

Expand All @@ -102,7 +105,10 @@ test.serial('cleans up request timeouts', withServer, async (t, server, got) =>
}
});

await t.throwsAsync(gotPromise, {instanceOf: CancelError});
await t.throwsAsync(gotPromise, {
instanceOf: CancelError,
code: 'ERR_CANCELED'
});

// Wait for unhandled errors
await delay(40);
Expand All @@ -124,7 +130,10 @@ test.serial('cancels in-progress request', withServerAndFakeTimers, async (t, se
body.push(null);
});

await t.throwsAsync(gotPromise, {instanceOf: CancelError});
await t.throwsAsync(gotPromise, {
instanceOf: CancelError,
code: 'ERR_CANCELED'
});
await t.notThrowsAsync(promise, 'Request finished instead of aborting.');
});

Expand All @@ -144,7 +153,10 @@ test.serial('cancels in-progress request with timeout', withServerAndFakeTimers,
body.push(null);
});

await t.throwsAsync(gotPromise, {instanceOf: CancelError});
await t.throwsAsync(gotPromise, {
instanceOf: CancelError,
code: 'ERR_CANCELED'
});
await t.notThrowsAsync(promise, 'Request finished instead of aborting.');
});

Expand Down Expand Up @@ -220,7 +232,10 @@ test.serial('throws on incomplete (canceled) response - promise #2', withServerA
promise.cancel();
});

await t.throwsAsync(promise, {instanceOf: got.CancelError});
await t.throwsAsync(promise, {
instanceOf: got.CancelError,
code: 'ERR_CANCELED'
});
});

test.serial('throws on incomplete (canceled) response - stream', withServerAndFakeTimers, async (t, server, got, clock) => {
Expand Down Expand Up @@ -250,7 +265,10 @@ test('throws when canceling cached request', withServer, async (t, server, got)
promise.cancel();
});

await t.throwsAsync(promise, {instanceOf: got.CancelError});
await t.throwsAsync(promise, {
instanceOf: got.CancelError,
code: 'ERR_CANCELED'
});
});

test('throws when canceling cached request #2', withServer, async (t, server, got) => {
Expand All @@ -265,5 +283,8 @@ test('throws when canceling cached request #2', withServer, async (t, server, go
const promise = got({cache});
promise.cancel();

await t.throwsAsync(promise, {instanceOf: got.CancelError});
await t.throwsAsync(promise, {
instanceOf: got.CancelError,
code: 'ERR_CANCELED'
});
});
7 changes: 5 additions & 2 deletions test/error.ts
Expand Up @@ -28,7 +28,7 @@ test('properties', withServer, async (t, server, got) => {
// Class fields will always be initialized, even though they are undefined
// A test to check for undefined is in place below
// t.false({}.hasOwnProperty.call(error, 'code'));
t.is(error.code, undefined);
t.is(error.code, 'ERR_NON_2XX_3XX_RESPONSE');
t.is(error.message, 'Response code 404 (Not Found)');
t.deepEqual(error.options.url, url);
t.is(error.response.headers.connection, 'close');
Expand All @@ -41,6 +41,7 @@ test('catches dns errors', async t => {
t.regex(error.message, /ENOTFOUND|EAI_AGAIN/);
t.is(error.options.url.host, 'doesntexist');
t.is(error.options.method, 'GET');
t.is(error.code, 'ENOTFOUND');
});

test('`options.body` form error message', async t => {
Expand Down Expand Up @@ -130,6 +131,7 @@ test('`http.request` error', async t => {
}
}), {
instanceOf: got.RequestError,
code: 'ERR_GEN_REQ_ERROR',
message: 'The header content contains invalid characters'
});
});
Expand Down Expand Up @@ -215,7 +217,8 @@ test('promise does not hang on timeout on HTTP error', withServer, async (t, ser
await t.throwsAsync(got({
timeout: 100
}), {
instanceOf: TimeoutError
instanceOf: TimeoutError,
code: 'ETIMEDOUT'
});
});

Expand Down
2 changes: 2 additions & 0 deletions test/http.ts
Expand Up @@ -92,6 +92,7 @@ test('doesn\'t throw if `options.throwHttpErrors` is false', withServer, async (
test('invalid protocol throws', async t => {
await t.throwsAsync(got('c:/nope.com').json(), {
instanceOf: UnsupportedProtocolError,
code: 'ERR_UNSUPPORTED_PROTOCOL',
message: 'Unsupported protocol "c:"'
});
});
Expand Down Expand Up @@ -225,6 +226,7 @@ test('throws an error if the server aborted the request', withServer, async (t,
});

const error = await t.throwsAsync<ReadError>(got(''), {
code: 'ECONNRESET',
message: 'The server aborted pending request'
});

Expand Down
1 change: 1 addition & 0 deletions test/post.ts
Expand Up @@ -354,6 +354,7 @@ test('throws on upload error', withServer, async (t, server, got) => {
}
})), {
instanceOf: UploadError,
code: 'ERR_UPLOAD',
message
});
});
10 changes: 8 additions & 2 deletions test/promise.ts
Expand Up @@ -71,8 +71,14 @@ test('promise.json() can be called before a file stream body is open', withServe

const promise = got({body});
const checks = [
t.throwsAsync(promise, {instanceOf: CancelError}),
t.throwsAsync(promise.json(), {instanceOf: CancelError})
t.throwsAsync(promise, {
instanceOf: CancelError,
code: 'ERR_CANCELED'
}),
t.throwsAsync(promise.json(), {
instanceOf: CancelError,
code: 'ERR_CANCELED'
})
];

promise.cancel();
Expand Down
8 changes: 6 additions & 2 deletions test/redirects.ts
Expand Up @@ -84,6 +84,7 @@ test('throws on endless redirects - default behavior', withServer, async (t, ser
const error = await t.throwsAsync<MaxRedirectsError>(got(''), {message: 'Redirected 10 times. Aborting.'});

t.deepEqual(error.response.redirectUrls, new Array(10).fill(`${server.url}/`));
t.is(error.code, 'ERR_MAX_REDIRECTS');
});

test('custom `maxRedirects` option', withServer, async (t, server, got) => {
Expand All @@ -97,6 +98,7 @@ test('custom `maxRedirects` option', withServer, async (t, server, got) => {
const error = await t.throwsAsync<MaxRedirectsError>(got('', {maxRedirects: 5}), {message: 'Redirected 5 times. Aborting.'});

t.deepEqual(error.response.redirectUrls, new Array(5).fill(`${server.url}/`));
t.is(error.code, 'ERR_MAX_REDIRECTS');
});

test('searchParams are not breaking redirects', withServer, async (t, server, got) => {
Expand All @@ -123,7 +125,8 @@ test('redirects GET and HEAD requests', withServer, async (t, server, got) => {
});

await t.throwsAsync(got.get(''), {
instanceOf: got.MaxRedirectsError
instanceOf: got.MaxRedirectsError,
code: 'ERR_MAX_REDIRECTS'
});
});

Expand All @@ -136,7 +139,8 @@ test('redirects POST requests', withServer, async (t, server, got) => {
});

await t.throwsAsync(got.post({body: 'wow'}), {
instanceOf: got.MaxRedirectsError
instanceOf: got.MaxRedirectsError,
code: 'ERR_MAX_REDIRECTS'
});
});

Expand Down
4 changes: 4 additions & 0 deletions test/response-parse.ts
Expand Up @@ -90,6 +90,7 @@ test('throws an error on invalid response type', withServer, async (t, server, g
t.regex(error.message, /^Unknown body type 'invalid'/);
t.true(error.message.includes(error.options.url.hostname));
t.is(error.options.url.pathname, '/');
t.is(error.code, 'ERR_BODY_PARSE_FAILURE');
});

test('wraps parsing errors', withServer, async (t, server, got) => {
Expand All @@ -100,6 +101,7 @@ test('wraps parsing errors', withServer, async (t, server, got) => {
const error = await t.throwsAsync<ParseError>(got({responseType: 'json'}), {instanceOf: got.ParseError});
t.true(error.message.includes(error.options.url.hostname));
t.is(error.options.url.pathname, '/');
t.is(error.code, 'ERR_BODY_PARSE_FAILURE');
});

test('parses non-200 responses', withServer, async (t, server, got) => {
Expand Down Expand Up @@ -136,6 +138,7 @@ test('parse errors have `response` property', withServer, async (t, server, got)

t.is(error.response.statusCode, 200);
t.is(error.response.body, '/');
t.is(error.code, 'ERR_BODY_PARSE_FAILURE');
});

test('sets correct headers', withServer, async (t, server, got) => {
Expand Down Expand Up @@ -186,6 +189,7 @@ test('shortcuts throw ParseErrors', withServer, async (t, server, got) => {

await t.throwsAsync(got('').json(), {
instanceOf: ParseError,
code: 'ERR_BODY_PARSE_FAILURE',
message: /^Unexpected token o in JSON at position 1 in/
});
});
Expand Down