Skip to content

Commit cdab4d1

Browse files
committed
Merge branch '22-handle-errors-thrown-by-a-routes-handle' into dev/zefir
2 parents 1bae72e + 3d10f97 commit cdab4d1

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

src/Server.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import packageJson from "../package.json" with {type: "json"};
44
import {Request} from "./Request.js";
55
import {EmptyResponse} from "./response/index.js";
66
import {Response} from "./response/Response.js";
7+
import {ThrowableResponse} from "./response/ThrowableResponse.js";
78
import {RouteRegistry} from "./routing/RouteRegistry.js";
89
import {ServerErrorRegistry} from "./ServerErrorRegistry.js";
910

@@ -109,9 +110,13 @@ class Server extends EventEmitter<Server.Events> {
109110
this.errors._get(ServerErrorRegistry.ErrorCodes.BAD_URL, null)._send(res, this);
110111
return;
111112
}
113+
112114
if (e instanceof Request.SocketClosedError)
113115
return;
114-
throw e;
116+
117+
this.emit("error", e as any);
118+
this.errors._get(ServerErrorRegistry.ErrorCodes.INTERNAL, null)._send(res, this);
119+
return;
115120
}
116121

117122
for (const [key, value] of this.globalHeaders)
@@ -127,7 +132,13 @@ class Server extends EventEmitter<Server.Events> {
127132
response = await this.routes.handle(apiRequest);
128133
}
129134
catch (e) {
130-
if (e instanceof RouteRegistry.NoRouteError)
135+
if (e instanceof ThrowableResponse) {
136+
response = e.getResponse();
137+
const cause = e.getError();
138+
if (cause !== null)
139+
this.emit("error", cause);
140+
}
141+
else if (e instanceof RouteRegistry.NoRouteError)
131142
response = this.errors._get(ServerErrorRegistry.ErrorCodes.NO_ROUTE, apiRequest);
132143
else {
133144
this.emit("error", e as any);

src/response/ThrowableResponse.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import {Response} from "./Response.js";
2+
3+
/**
4+
* An (error) response that is thrown. Will be caught by the server and sent to the client.
5+
*/
6+
export class ThrowableResponse<T extends Response> extends Error {
7+
public override name = ThrowableResponse.name;
8+
9+
/**
10+
* The response to send to the client.
11+
*/
12+
protected readonly response: T;
13+
14+
/**
15+
* An optional error to emit on the server’s error event.
16+
*/
17+
protected readonly error: Error | null;
18+
19+
/**
20+
* Create a new throwable response.
21+
* @param response The response to send to the client.
22+
* @param [error] An optional error to emit on the server’s error event.
23+
*/
24+
public constructor(response: T, error?: Error) {
25+
super();
26+
this.response = response;
27+
this.error = error ?? null;
28+
}
29+
30+
public getResponse(): T {
31+
return this.response;
32+
}
33+
34+
public getError(): Error | null {
35+
return this.error;
36+
}
37+
}

src/response/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export * from "./EmptyResponse.js";
44
export * from "./JsonResponse.js";
55
export * from "./Response.js";
66
export * from "./TextResponse.js";
7+
export * from "./ThrowableResponse.js";

0 commit comments

Comments
 (0)