Skip to content

Commit 487082b

Browse files
authoredJun 11, 2021
feat: error.response. Deprecates error.headers (#194)
1 parent 4c6f85f commit 487082b

File tree

4 files changed

+117
-42
lines changed

4 files changed

+117
-42
lines changed
 

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ const error = new RequestError("Oops", 500, {
5555

5656
error.message; // Oops
5757
error.status; // 500
58-
error.headers; // { 'x-github-request-id': '1:2:3:4' }
5958
error.request.method; // POST
6059
error.request.url; // https://api.github.com/foo
6160
error.request.body; // { bar: 'baz' }
6261
error.request.headers; // { authorization: 'token [REDACTED]' }
62+
error.response; // { url, status, headers, data }
6363
```
6464

6565
## LICENSE

‎src/index.ts

+49-16
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import { Deprecation } from "deprecation";
22
import once from "once";
3-
const logOnce = once((deprecation: any) => console.warn(deprecation));
3+
const logOnceCode = once((deprecation: any) => console.warn(deprecation));
4+
const logOnceHeaders = once((deprecation: any) => console.warn(deprecation));
45

5-
import { RequestOptions, ResponseHeaders } from "@octokit/types";
6+
import {
7+
RequestOptions,
8+
ResponseHeaders,
9+
OctokitResponse,
10+
} from "@octokit/types";
611
import { RequestErrorOptions } from "./types";
712

813
/**
@@ -23,15 +28,22 @@ export class RequestError extends Error {
2328
*/
2429
code!: number;
2530

31+
/**
32+
* Request options that lead to the error.
33+
*/
34+
request: RequestOptions;
35+
2636
/**
2737
* error response headers
38+
*
39+
* @deprecated `error.headers` is deprecated in favor of `error.response.headers`
2840
*/
29-
headers: ResponseHeaders;
41+
headers!: ResponseHeaders;
3042

3143
/**
32-
* Request options that lead to the error.
44+
* Response object if a response was received
3345
*/
34-
request: RequestOptions;
46+
response?: OctokitResponse<unknown>;
3547

3648
constructor(
3749
message: string,
@@ -48,17 +60,16 @@ export class RequestError extends Error {
4860

4961
this.name = "HttpError";
5062
this.status = statusCode;
51-
Object.defineProperty(this, "code", {
52-
get() {
53-
logOnce(
54-
new Deprecation(
55-
"[@octokit/request-error] `error.code` is deprecated, use `error.status`."
56-
)
57-
);
58-
return statusCode;
59-
},
60-
});
61-
this.headers = options.headers || {};
63+
let headers: ResponseHeaders;
64+
65+
if ("headers" in options && typeof options.headers !== "undefined") {
66+
headers = options.headers;
67+
}
68+
69+
if ("response" in options) {
70+
this.response = options.response;
71+
headers = options.response.headers;
72+
}
6273

6374
// redact request credentials without mutating original request options
6475
const requestCopy = Object.assign({}, options.request);
@@ -80,5 +91,27 @@ export class RequestError extends Error {
8091
.replace(/\baccess_token=\w+/g, "access_token=[REDACTED]");
8192

8293
this.request = requestCopy;
94+
95+
// deprecations
96+
Object.defineProperty(this, "code", {
97+
get() {
98+
logOnceCode(
99+
new Deprecation(
100+
"[@octokit/request-error] `error.code` is deprecated, use `error.status`."
101+
)
102+
);
103+
return statusCode;
104+
},
105+
});
106+
Object.defineProperty(this, "headers", {
107+
get() {
108+
logOnceHeaders(
109+
new Deprecation(
110+
"[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`."
111+
)
112+
);
113+
return headers || {};
114+
},
115+
});
83116
}
84117
}

‎src/types.ts

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1-
import { RequestOptions, ResponseHeaders } from "@octokit/types";
1+
import {
2+
RequestOptions,
3+
ResponseHeaders,
4+
OctokitResponse,
5+
} from "@octokit/types";
26

3-
export type RequestErrorOptions = {
4-
headers?: ResponseHeaders;
5-
request: RequestOptions;
6-
};
7+
export type RequestErrorOptions =
8+
| {
9+
/** @deprecated set `response` instead */
10+
headers?: ResponseHeaders;
11+
request: RequestOptions;
12+
}
13+
| {
14+
response: OctokitResponse<unknown>;
15+
request: RequestOptions;
16+
};

‎test/request-error.test.ts

+52-20
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,27 @@ const mockOptions: RequestErrorOptions = {
1010
};
1111

1212
describe("RequestError", () => {
13-
it("inherits from Error", () => {
13+
test("inherits from Error", () => {
1414
const error = new RequestError("test", 123, mockOptions);
1515
expect(error).toBeInstanceOf(Error);
1616
});
1717

18-
it("sets .name to 'RequestError'", () => {
18+
test("sets .name to 'RequestError'", () => {
1919
const error = new RequestError("test", 123, mockOptions);
2020
expect(error.name).toBe("HttpError");
2121
});
2222

23-
it("sets .message", () => {
23+
test("sets .message", () => {
2424
expect(new RequestError("test", 123, mockOptions).message).toEqual("test");
2525
expect(new RequestError("foo", 123, mockOptions).message).toEqual("foo");
2626
});
2727

28-
it("sets .status", () => {
28+
test("sets .status", () => {
2929
expect(new RequestError("test", 123, mockOptions).status).toEqual(123);
3030
expect(new RequestError("test", 404, mockOptions).status).toEqual(404);
3131
});
3232

33-
it("sets .headers", () => {
34-
const options = Object.assign({}, mockOptions, {
35-
headers: {
36-
foo: "bar",
37-
},
38-
});
39-
expect(new RequestError("test", 123, options).headers).toEqual({
40-
foo: "bar",
41-
});
42-
});
43-
44-
it("sets .request", () => {
33+
test("sets .request", () => {
4534
const options = Object.assign({}, mockOptions, {
4635
request: {
4736
method: "POST",
@@ -67,7 +56,7 @@ describe("RequestError", () => {
6756
});
6857
});
6958

70-
it("redacts credentials from error.request.url", () => {
59+
test("redacts credentials from error.request.url", () => {
7160
const options = Object.assign({}, mockOptions, {
7261
request: {
7362
method: "GET",
@@ -83,7 +72,7 @@ describe("RequestError", () => {
8372
);
8473
});
8574

86-
it("redacts client_secret from error.request.url", () => {
75+
test("redacts client_secret from error.request.url", () => {
8776
const options = Object.assign({}, mockOptions, {
8877
request: {
8978
method: "GET",
@@ -99,7 +88,7 @@ describe("RequestError", () => {
9988
);
10089
});
10190

102-
it("redacts access_token from error.request.url", () => {
91+
test("redacts access_token from error.request.url", () => {
10392
const options = Object.assign({}, mockOptions, {
10493
request: {
10594
method: "GET",
@@ -115,10 +104,53 @@ describe("RequestError", () => {
115104
);
116105
});
117106

118-
it("deprecates .code", () => {
107+
test("error.response", () => {
108+
const error = new RequestError("test", 123, {
109+
request: mockOptions.request,
110+
response: {
111+
url: mockOptions.request.url,
112+
status: 404,
113+
data: {
114+
error: "Not Found",
115+
},
116+
headers: {
117+
"x-github-request-id": "1",
118+
},
119+
},
120+
});
121+
122+
expect(error.response).toStrictEqual({
123+
data: {
124+
error: "Not Found",
125+
},
126+
headers: {
127+
"x-github-request-id": "1",
128+
},
129+
status: 404,
130+
url: "https://api.github.com/",
131+
});
132+
});
133+
134+
test("deprecates .code", () => {
119135
global.console.warn = jest.fn();
120136
expect(new RequestError("test", 123, mockOptions).code).toEqual(123);
121137
expect(new RequestError("test", 404, mockOptions).code).toEqual(404);
122138
expect(console.warn).toHaveBeenCalledTimes(1);
123139
});
140+
141+
test("deprecates .headers", () => {
142+
global.console.warn = jest.fn();
143+
expect(new RequestError("test", 123, mockOptions).headers).toStrictEqual(
144+
{}
145+
);
146+
expect(
147+
new RequestError("test", 404, { ...mockOptions, headers: { foo: "bar" } })
148+
.headers
149+
).toStrictEqual({ foo: "bar" });
150+
expect(
151+
new RequestError("test", 404, { ...mockOptions, headers: undefined })
152+
.headers
153+
).toStrictEqual({});
154+
expect(console.warn).toHaveBeenCalledTimes(1);
155+
});
124156
});

0 commit comments

Comments
 (0)
Please sign in to comment.