Skip to content

Commit 94f3455

Browse files
committed
add error classes for http errors
1 parent 4998d6b commit 94f3455

File tree

4 files changed

+421
-0
lines changed

4 files changed

+421
-0
lines changed

packages/event-handler/src/rest/constants.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ export const HttpVerbs = {
1010
OPTIONS: 'OPTIONS',
1111
} as const;
1212

13+
export const HttpErrorCodes = {
14+
BAD_REQUEST: 400,
15+
UNAUTHORIZED: 401,
16+
FORBIDDEN: 403,
17+
NOT_FOUND: 404,
18+
METHOD_NOT_ALLOWED: 405,
19+
REQUEST_TIMEOUT: 408,
20+
REQUEST_ENTITY_TOO_LARGE: 413,
21+
INTERNAL_SERVER_ERROR: 500,
22+
SERVICE_UNAVAILABLE: 503,
23+
} as const;
24+
1325
export const PARAM_PATTERN = /:([a-zA-Z_]\w*)(?=\/|$)/g;
1426

1527
export const SAFE_CHARS = "-._~()'!*:@,;=+&$";

packages/event-handler/src/rest/errors.ts

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import type { ErrorResponse } from '../types/rest.js';
2+
import { HttpErrorCodes } from './constants.js';
3+
14
export class RouteMatchingError extends Error {
25
constructor(
36
message: string,
@@ -15,3 +18,145 @@ export class ParameterValidationError extends RouteMatchingError {
1518
this.name = 'ParameterValidationError';
1619
}
1720
}
21+
22+
abstract class ServiceError extends Error {
23+
abstract readonly statusCode: number;
24+
abstract readonly errorType: string;
25+
public readonly details?: Record<string, unknown>;
26+
27+
constructor(
28+
message: string,
29+
options?: ErrorOptions,
30+
details?: Record<string, unknown>
31+
) {
32+
super(message, options);
33+
this.name = 'ServiceError';
34+
this.details = details;
35+
}
36+
37+
toJSON(): ErrorResponse {
38+
return {
39+
statusCode: this.statusCode,
40+
error: this.errorType,
41+
message: this.message,
42+
...(this.details && { details: this.details }),
43+
};
44+
}
45+
}
46+
47+
export class BadRequestError extends ServiceError {
48+
readonly statusCode = HttpErrorCodes.BAD_REQUEST;
49+
readonly errorType = 'BadRequestError';
50+
51+
constructor(
52+
message?: string,
53+
options?: ErrorOptions,
54+
details?: Record<string, unknown>
55+
) {
56+
super(message ?? 'Bad request', options, details);
57+
}
58+
}
59+
60+
export class UnauthorizedError extends ServiceError {
61+
readonly statusCode = HttpErrorCodes.UNAUTHORIZED;
62+
readonly errorType = 'UnauthorizedError';
63+
64+
constructor(
65+
message?: string,
66+
options?: ErrorOptions,
67+
details?: Record<string, unknown>
68+
) {
69+
super(message ?? 'Unauthorized', options, details);
70+
}
71+
}
72+
73+
export class ForbiddenError extends ServiceError {
74+
readonly statusCode = HttpErrorCodes.FORBIDDEN;
75+
readonly errorType = 'ForbiddenError';
76+
77+
constructor(
78+
message?: string,
79+
options?: ErrorOptions,
80+
details?: Record<string, unknown>
81+
) {
82+
super(message ?? 'Forbidden', options, details);
83+
}
84+
}
85+
86+
export class NotFoundError extends ServiceError {
87+
readonly statusCode = HttpErrorCodes.NOT_FOUND;
88+
readonly errorType = 'NotFoundError';
89+
90+
constructor(
91+
message?: string,
92+
options?: ErrorOptions,
93+
details?: Record<string, unknown>
94+
) {
95+
super(message ?? 'Not found', options, details);
96+
}
97+
}
98+
99+
export class MethodNotAllowedError extends ServiceError {
100+
readonly statusCode = HttpErrorCodes.METHOD_NOT_ALLOWED;
101+
readonly errorType = 'MethodNotAllowedError';
102+
103+
constructor(
104+
message?: string,
105+
options?: ErrorOptions,
106+
details?: Record<string, unknown>
107+
) {
108+
super(message ?? 'Method not allowed', options, details);
109+
}
110+
}
111+
112+
export class RequestTimeoutError extends ServiceError {
113+
readonly statusCode = HttpErrorCodes.REQUEST_TIMEOUT;
114+
readonly errorType = 'RequestTimeoutError';
115+
116+
constructor(
117+
message?: string,
118+
options?: ErrorOptions,
119+
details?: Record<string, unknown>
120+
) {
121+
super(message ?? 'Request timeout', options, details);
122+
}
123+
}
124+
125+
export class RequestEntityTooLargeError extends ServiceError {
126+
readonly statusCode = HttpErrorCodes.REQUEST_ENTITY_TOO_LARGE;
127+
readonly errorType = 'RequestEntityTooLargeError';
128+
129+
constructor(
130+
message?: string,
131+
options?: ErrorOptions,
132+
details?: Record<string, unknown>
133+
) {
134+
super(message ?? 'Request entity too large', options, details);
135+
}
136+
}
137+
138+
export class InternalServerError extends ServiceError {
139+
readonly statusCode = HttpErrorCodes.INTERNAL_SERVER_ERROR;
140+
readonly errorType = 'InternalServerError';
141+
142+
constructor(
143+
message?: string,
144+
options?: ErrorOptions,
145+
details?: Record<string, unknown>
146+
) {
147+
super(message ?? 'Internal server error', options, details);
148+
}
149+
}
150+
151+
export class ServiceUnavailableError extends ServiceError {
152+
readonly statusCode = HttpErrorCodes.SERVICE_UNAVAILABLE;
153+
readonly errorType = 'ServiceUnavailableError';
154+
155+
constructor(
156+
message?: string,
157+
options?: ErrorOptions,
158+
details?: Record<string, unknown>
159+
) {
160+
super(message ?? 'Service unavailable', options, details);
161+
}
162+
}

packages/event-handler/src/types/rest.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ import type { BaseRouter } from '../rest/BaseRouter.js';
33
import type { HttpVerbs } from '../rest/constants.js';
44
import type { Route } from '../rest/Route.js';
55

6+
type ErrorResponse = {
7+
statusCode: number;
8+
error: string;
9+
message: string;
10+
};
11+
612
/**
713
* Options for the {@link BaseRouter} class
814
*/
@@ -59,6 +65,7 @@ type ValidationResult = {
5965
export type {
6066
CompiledRoute,
6167
DynamicRoute,
68+
ErrorResponse,
6269
HttpMethod,
6370
Path,
6471
RouterOptions,

0 commit comments

Comments
 (0)