@@ -16,6 +16,11 @@ import type {
1616} from '../types/rest.js' ;
1717import { HttpVerbs } from './constants.js' ;
1818import { ErrorHandlerRegistry } from './ErrorHandlerRegistry.js' ;
19+ import {
20+ MethodNotAllowedError ,
21+ NotFoundError ,
22+ ServiceError ,
23+ } from './errors.js' ;
1924import { Route } from './Route.js' ;
2025import { RouteHandlerRegistry } from './RouteHandlerRegistry.js' ;
2126
@@ -54,13 +59,37 @@ abstract class BaseRouter {
5459 this . isDev = isDevMode ( ) ;
5560 }
5661
62+ /**
63+ * Registers a custom error handler for specific error types.
64+ *
65+ * @param errorType - The error constructor(s) to handle
66+ * @param handler - The error handler function that returns an ErrorResponse
67+ */
5768 public errorHandler < T extends Error > (
5869 errorType : ErrorConstructor < T > | ErrorConstructor < T > [ ] ,
5970 handler : ErrorHandler < T >
6071 ) : void {
6172 this . errorHandlerRegistry . register ( errorType , handler ) ;
6273 }
6374
75+ /**
76+ * Registers a custom handler for 404 Not Found errors.
77+ *
78+ * @param handler - The error handler function for NotFoundError
79+ */
80+ public notFound ( handler : ErrorHandler < NotFoundError > ) : void {
81+ this . errorHandlerRegistry . register ( NotFoundError , handler ) ;
82+ }
83+
84+ /**
85+ * Registers a custom handler for 405 Method Not Allowed errors.
86+ *
87+ * @param handler - The error handler function for MethodNotAllowedError
88+ */
89+ public methodNotAllowed ( handler : ErrorHandler < MethodNotAllowedError > ) : void {
90+ this . errorHandlerRegistry . register ( MethodNotAllowedError , handler ) ;
91+ }
92+
6493 public abstract resolve (
6594 event : unknown ,
6695 context : Context ,
@@ -76,6 +105,62 @@ abstract class BaseRouter {
76105 }
77106 }
78107
108+ /**
109+ * Handles errors by finding a registered error handler or falling
110+ * back to a default handler.
111+ *
112+ * @param error - The error to handle
113+ * @returns A Response object with appropriate status code and error details
114+ */
115+ protected async handleError ( error : Error ) : Promise < Response > {
116+ const handler = this . errorHandlerRegistry . resolve ( error ) ;
117+ if ( handler !== null ) {
118+ try {
119+ const body = await handler ( error ) ;
120+ return new Response ( JSON . stringify ( body ) , {
121+ status : body . statusCode ,
122+ headers : { 'Content-Type' : 'application/json' } ,
123+ } ) ;
124+ } catch ( handlerError ) {
125+ return this . #defaultErrorHandler( handlerError as Error ) ;
126+ }
127+ }
128+
129+ if ( error instanceof ServiceError ) {
130+ return new Response ( JSON . stringify ( error . toJSON ( ) ) , {
131+ status : error . statusCode ,
132+ headers : { 'Content-Type' : 'application/json' } ,
133+ } ) ;
134+ }
135+
136+ return this . #defaultErrorHandler( error ) ;
137+ }
138+
139+ /**
140+ * Default error handler that returns a 500 Internal Server Error response.
141+ * In development mode, includes stack trace and error details.
142+ *
143+ * @param error - The error to handle
144+ * @returns A Response object with 500 status and error details
145+ */
146+ #defaultErrorHandler( error : Error ) : Response {
147+ return new Response (
148+ JSON . stringify ( {
149+ statusCode : 500 ,
150+ error : 'Internal Server Error' ,
151+ message : isDevMode ( ) ? error . message : 'Internal Server Error' ,
152+ ...( isDevMode ( ) && {
153+ stack : error . stack ,
154+ details : { errorName : error . name } ,
155+ } ) ,
156+ } ) ,
157+ {
158+ status : 500 ,
159+ headers : { 'Content-Type' : 'application/json' } ,
160+ }
161+ ) ;
162+ }
163+
79164 #handleHttpMethod(
80165 method : HttpMethod ,
81166 path : Path ,
0 commit comments