11import { Readable } from 'node:stream' ;
22import { pipeline } from 'node:stream/promises' ;
33import type streamWeb from 'node:stream/web' ;
4- import type { GenericLogger } from '@aws-lambda-powertools/commons/types' ;
4+ import type {
5+ GenericLogger ,
6+ JSONValue ,
7+ } from '@aws-lambda-powertools/commons/types' ;
8+ import { isRecord } from '@aws-lambda-powertools/commons/typeutils' ;
59import {
610 getStringFromEnv ,
711 isDevMode ,
@@ -457,19 +461,7 @@ class Router {
457461 ) {
458462 return body ;
459463 }
460- if ( ! body . statusCode ) {
461- if ( error instanceof NotFoundError ) {
462- body . statusCode = HttpStatusCodes . NOT_FOUND ;
463- } else if ( error instanceof MethodNotAllowedError ) {
464- body . statusCode = HttpStatusCodes . METHOD_NOT_ALLOWED ;
465- }
466- }
467- return new Response ( JSON . stringify ( body ) , {
468- status :
469- ( body . statusCode as number ) ??
470- HttpStatusCodes . INTERNAL_SERVER_ERROR ,
471- headers : { 'Content-Type' : 'application/json' } ,
472- } ) ;
464+ return this . #errorBodyToWebResponse( body , error ) ;
473465 } catch ( handlerError ) {
474466 if ( handlerError instanceof HttpError ) {
475467 return await this . handleError ( handlerError , options ) ;
@@ -488,6 +480,48 @@ class Router {
488480 return this . #defaultErrorHandler( error ) ;
489481 }
490482
483+ /**
484+ * Converts an error handler's response body to an HTTP Response object.
485+ *
486+ * If the body is a record object without a status code, sets the status code for
487+ * NotFoundError (404) or MethodNotAllowedError (405). Uses the status code from
488+ * the body if present, otherwise defaults to 500 Internal Server Error.
489+ *
490+ * @param body - The response body returned by the error handler, of type JSONValue
491+ * @param error - The Error object associated with the response
492+ */
493+ #errorBodyToWebResponse( body : JSONValue , error : Error ) : Response {
494+ let status : number = HttpStatusCodes . INTERNAL_SERVER_ERROR ;
495+
496+ if ( isRecord ( body ) ) {
497+ body . statusCode = body . statusCode ?? this . #getStatusCodeFromError( error ) ;
498+ status = ( body . statusCode as number ) ?? status ;
499+ }
500+
501+ return new Response ( JSON . stringify ( body ) , {
502+ status,
503+ headers : { 'Content-Type' : 'application/json' } ,
504+ } ) ;
505+ }
506+
507+ /**
508+ * Extracts the HTTP status code from an error instance.
509+ *
510+ * Maps specific error types to their corresponding HTTP status codes:
511+ * - `NotFoundError` maps to 404 (NOT_FOUND)
512+ * - `MethodNotAllowedError` maps to 405 (METHOD_NOT_ALLOWED)
513+ *
514+ * @param error - The error instance to extract the status code from
515+ */
516+ #getStatusCodeFromError( error : Error ) : number | undefined {
517+ if ( error instanceof NotFoundError ) {
518+ return HttpStatusCodes . NOT_FOUND ;
519+ }
520+ if ( error instanceof MethodNotAllowedError ) {
521+ return HttpStatusCodes . METHOD_NOT_ALLOWED ;
522+ }
523+ }
524+
491525 /**
492526 * Default error handler that returns a 500 Internal Server Error response.
493527 * In development mode, includes stack trace and error details.
0 commit comments