From 22d58fb43aece59b3bc571c46f7eda7271f8e083 Mon Sep 17 00:00:00 2001 From: IswaryaS Date: Sun, 22 May 2022 18:23:32 +0530 Subject: [PATCH] Add `response.ok` (#2043) Co-authored-by: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Co-authored-by: Iswarya Sankaran --- documentation/3-streams.md | 12 ++++++++++++ source/core/index.ts | 1 + source/core/response.ts | 7 +++++++ test/http.ts | 40 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+) diff --git a/documentation/3-streams.md b/documentation/3-streams.md index 854185189..ec029dcc4 100644 --- a/documentation/3-streams.md +++ b/documentation/3-streams.md @@ -354,6 +354,18 @@ The server's IP address. Whether the response comes from cache or not. +### `ok` + +**Type: `boolean`** + +Whether the response was successful + +**Note:** +> - A request is successful when the status code of the final request is `2xx` or `3xx`. +> - When [following redirects](2-options.md#followredirect), a request is successful **only** when the status code of the final request is `2xx`. +> - `304` responses are always considered successful. +> - Got throws automatically when `response.ok` is `false` and `throwHttpErrors` is `true`. + ### `statusCode` **Type: `number`** diff --git a/source/core/index.ts b/source/core/index.ts index 1d913c265..63e2c5e7b 100644 --- a/source/core/index.ts +++ b/source/core/index.ts @@ -632,6 +632,7 @@ export default class Request extends Duplex implements RequestEvents { typedResponse.isFromCache = (this._nativeResponse as any).fromCache ?? false; typedResponse.ip = this.ip; typedResponse.retryCount = this.retryCount; + typedResponse.ok = isResponseOk(typedResponse); this._isFromCache = typedResponse.isFromCache; diff --git a/source/core/response.ts b/source/core/response.ts index 413dcad4a..6fee258b0 100644 --- a/source/core/response.ts +++ b/source/core/response.ts @@ -91,6 +91,13 @@ export interface PlainResponse extends IncomingMessageWithTimings { The result of the request. */ body?: unknown; + + /** + Whether the response was successful. + + __Note__: Got throws automatically when `response.ok` is `false` and `throwHttpErrors` is `true`. + */ + ok: boolean; } // For Promise support diff --git a/test/http.ts b/test/http.ts index 8ff23637c..662129461 100644 --- a/test/http.ts +++ b/test/http.ts @@ -375,3 +375,43 @@ test('ClientRequest can throw before promise resolves', async t => { message: /EINVAL|EHOSTUNREACH|ETIMEDOUT/, }); }); + +test('status code 200 has response ok is true', withServer, async (t, server, got) => { + server.get('/', (_request, response) => { + response.statusCode = 200; + response.end(); + }); + + const promise = got(''); + await t.notThrowsAsync(promise); + const {statusCode, body, ok} = await promise; + t.true(ok); + t.is(statusCode, 200); + t.is(body, ''); +}); + +test('status code 404 has response ok is false if error is not thrown', withServer, async (t, server, got) => { + server.get('/', (_request, response) => { + response.statusCode = 404; + response.end(); + }); + + const promise = got('', {throwHttpErrors: false}); + await t.notThrowsAsync(promise); + const {statusCode, body, ok} = await promise; + t.is(ok, false); + t.is(statusCode, 404); + t.is(body, ''); +}); + +test('status code 404 has error response ok is false if error is thrown', withServer, async (t, server, got) => { + server.get('/', (_request, response) => { + response.statusCode = 404; + response.end('not'); + }); + + const error = await t.throwsAsync(got(''), {instanceOf: HTTPError}); + t.is(error.response.statusCode, 404); + t.is(error.response.ok, false); + t.is(error.response.body, 'not'); +});