Skip to content

Commit

Permalink
Adding explicit error types for easier debugging
Browse files Browse the repository at this point in the history
  • Loading branch information
jdalrymple committed Dec 25, 2023
1 parent 6166bc6 commit 51674a1
Show file tree
Hide file tree
Showing 7 changed files with 1,006 additions and 1,172 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/1-bug.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ about: Something is not working as it should

- Node.js version:
- Gitbeaker version:
- Gitbeaker release (cli, node, browser, core, requester-utils):
- Gitbeaker release (cli, rest, core, requester-utils):
- OS & version:

<!-- *(Brief description of your issue here)*
Expand Down
31 changes: 31 additions & 0 deletions packages/requester-utils/src/GitbeakerError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint-disable max-classes-per-file */
export class GitbeakerRequestError extends Error {
constructor(
message: string,
options?: {
cause: {
description: string;
request: Request;
response: Response;
};
},
) {
super(message, options);

this.name = 'GitbeakerRequestError';
}
}

export class GitbeakerTimeoutError extends Error {
constructor(message: string) {
super(message);
this.name = 'GitbeakerTimeoutError';
}
}

export class GitbeakerRetryError extends Error {
constructor(message: string) {
super(message);
this.name = 'GitbeakerTimeoutError';
}
}
1 change: 1 addition & 0 deletions packages/requester-utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './RequesterUtils';
export * from './BaseResource';
export * from './GitbeakerError';
23 changes: 16 additions & 7 deletions packages/rest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,17 +339,26 @@ const api = new Gitlab({

Request errors are returned back within a plain Error instance, using the cause to hold the original response and a text description of the error pulled from the response's error or message fields if JSON, or its plain text value:

```js
Error: Bad Request
<stack trace>
{
[cause]: {
description: <text description>,
response: <original Response object>
```ts
class GitbeakerError extends Error {
constructor(
message: string,
options?: {
cause: {
description: string;
request: Request;
response: Response;
};
},
) {
super(message, options);
this.name = 'GitbeakerError';
}
}
```

Note, the message is assigned to the Response's `statusText`, and the [Request](https://nodejs.org/dist/latest-v18.x/docs/api/globals.html#request) and [Response](https://nodejs.org/dist/latest-v18.x/docs/api/globals.html#response) types are from the NodeJS API.

## Examples

Once you have your library instantiated, you can utilize many of the API's functionality:
Expand Down
19 changes: 14 additions & 5 deletions packages/rest/src/Requester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import type {
ResourceOptions,
ResponseBodyTypes,
} from '@gitbeaker/requester-utils';
import { createRequesterFn, getMatchingRateLimiter } from '@gitbeaker/requester-utils';
import {
GitbeakerRequestError,
GitbeakerRetryError,
GitbeakerTimeoutError,
createRequesterFn,
getMatchingRateLimiter,
} from '@gitbeaker/requester-utils';

export async function defaultOptionsHandler(
resourceOptions: ResourceOptions,
Expand Down Expand Up @@ -63,7 +69,10 @@ async function parseResponse(response: Response, asStream = false) {
return { body, headers, status };
}

async function throwFailedRequestError(request: Request, response: Response) {
async function throwFailedRequestError(
request: Request,
response: Response,
): Promise<GitbeakerRequestError> {
const content = await response.text();
const contentType = response.headers.get('Content-Type');
let description = 'API Request Error';
Expand All @@ -76,7 +85,7 @@ async function throwFailedRequestError(request: Request, response: Response) {
description = content;
}

throw new Error(response.statusText, {
throw new GitbeakerRequestError(response.statusText, {
cause: {
description,
request,
Expand Down Expand Up @@ -114,7 +123,7 @@ export async function defaultRequestHandler(endpoint: string, options?: RequestO

const response = await fetch(request).catch((e) => {
if (e.name === 'TimeoutError' || e.name === 'AbortError') {
throw new Error('Query timeout was reached');
throw new GitbeakerTimeoutError('Query timeout was reached');
}

throw e;
Expand All @@ -131,7 +140,7 @@ export async function defaultRequestHandler(endpoint: string, options?: RequestO
}
/* eslint-enable */

throw new Error(
throw new GitbeakerRetryError(
`Could not successfully complete this request due to Error 429. Check the applicable rate limits for this endpoint.`,
);
}
Expand Down
10 changes: 5 additions & 5 deletions packages/rest/test/unit/Requester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ describe('defaultRequestHandler', () => {

await expect(defaultRequestHandler('http://test.com', {} as RequestOptions)).rejects.toThrow({
message: 'Really Bad Error',
name: 'Error',
name: 'GitbeakerRequestError',
cause: {
description: 'msg',
},
Expand All @@ -141,7 +141,7 @@ describe('defaultRequestHandler', () => {

await expect(defaultRequestHandler('http://test.com', {} as RequestOptions)).rejects.toThrow({
message: 'Really Bad Error',
name: 'Error',
name: 'GitbeakerRequestError',
cause: {
description: stringBody,
},
Expand All @@ -160,7 +160,7 @@ describe('defaultRequestHandler', () => {

await expect(defaultRequestHandler('http://test.com', {} as RequestOptions)).rejects.toThrow({
message: 'Query timeout was reached',
name: 'Error',
name: 'GitbeakerTimeoutError',
});
});

Expand All @@ -176,7 +176,7 @@ describe('defaultRequestHandler', () => {

await expect(defaultRequestHandler('http://test.com', {} as RequestOptions)).rejects.toThrow({
message: 'Query timeout was reached',
name: 'Error',
name: 'GitbeakerTimeoutError',
});
});

Expand Down Expand Up @@ -287,7 +287,7 @@ describe('defaultRequestHandler', () => {
await expect(defaultRequestHandler('http://test.com', {} as RequestOptions)).rejects.toThrow({
message:
'Could not successfully complete this request due to Error 429. Check the applicable rate limits for this endpoint.',
name: 'Error',
name: 'GitbeakerRetryError',
});

MockFetch.mockRestore();
Expand Down
Loading

0 comments on commit 51674a1

Please sign in to comment.