@@ -19,54 +19,38 @@ Middleware errorHandler() {
1919 } on HtHttpException catch (e, stackTrace) {
2020 // Handle specific HtHttpExceptions from the client/repository layers
2121 final statusCode = _mapExceptionToStatusCode (e);
22- final errorCode = _mapExceptionToCodeString (e);
2322 print ('HtHttpException Caught: $e \n $stackTrace ' ); // Log for debugging
24- return Response . json (
23+ return _jsonErrorResponse (
2524 statusCode: statusCode,
26- body: {
27- 'error' : {'code' : errorCode, 'message' : e.message},
28- },
25+ exception: e,
26+ context: context,
2927 );
3028 } on CheckedFromJsonException catch (e, stackTrace) {
3129 // Handle json_serializable validation errors. These are client errors.
3230 final field = e.key ?? 'unknown' ;
3331 final message = 'Invalid request body: Field "$field " has an '
3432 'invalid value or is missing. ${e .message }' ;
3533 print ('CheckedFromJsonException Caught: $e \n $stackTrace ' );
36- return Response . json (
34+ return _jsonErrorResponse (
3735 statusCode: HttpStatus .badRequest, // 400
38- body: {
39- 'error' : {
40- 'code' : 'invalidField' ,
41- 'message' : message,
42- },
43- },
36+ exception: InvalidInputException (message),
37+ context: context,
4438 );
4539 } on FormatException catch (e, stackTrace) {
4640 // Handle data format/parsing errors (often indicates bad client input)
4741 print ('FormatException Caught: $e \n $stackTrace ' ); // Log for debugging
48- return Response . json (
42+ return _jsonErrorResponse (
4943 statusCode: HttpStatus .badRequest, // 400
50- body: {
51- 'error' : {
52- 'code' : 'invalidFormat' ,
53- 'message' : 'Invalid data format: ${e .message }' ,
54- },
55- },
44+ exception: InvalidInputException ('Invalid data format: ${e .message }' ),
45+ context: context,
5646 );
5747 } catch (e, stackTrace) {
5848 // Handle any other unexpected errors
5949 print ('Unhandled Exception Caught: $e \n $stackTrace ' );
60- return Response . json (
50+ return _jsonErrorResponse (
6151 statusCode: HttpStatus .internalServerError, // 500
62- body: {
63- 'error' : {
64- 'code' : 'internalServerError' ,
65- 'message' : 'An unexpected internal server error occurred.' ,
66- // Avoid leaking sensitive details in production responses
67- // 'details': e.toString(), // Maybe include in dev mode only
68- },
69- },
52+ exception: const UnknownException ('An unexpected internal server error occurred.' ),
53+ context: context,
7054 );
7155 }
7256 };
@@ -108,3 +92,41 @@ String _mapExceptionToCodeString(HtHttpException exception) {
10892 _ => 'unknownError' , // Default
10993 };
11094}
95+
96+ /// Creates a standardized JSON error response with appropriate CORS headers.
97+ ///
98+ /// This helper ensures that error responses sent to the client include the
99+ /// necessary `Access-Control-Allow-Origin` header, allowing the client-side
100+ /// application to read the error message body.
101+ Response _jsonErrorResponse ({
102+ required int statusCode,
103+ required HtHttpException exception,
104+ required RequestContext context,
105+ }) {
106+ final errorCode = _mapExceptionToCodeString (exception);
107+ final headers = < String , String > {
108+ HttpHeaders .contentTypeHeader: 'application/json' ,
109+ };
110+
111+ // Add CORS headers to error responses to allow the client to read them.
112+ // This logic mirrors the behavior of `shelf_cors_headers` for development.
113+ final origin = context.request.headers['Origin' ];
114+ if (origin != null ) {
115+ // A simple check for localhost development environments.
116+ // For production, this should be a more robust check against a list
117+ // of allowed origins from environment variables.
118+ if (Uri .tryParse (origin)? .host == 'localhost' ) {
119+ headers[HttpHeaders .accessControlAllowOriginHeader] = origin;
120+ headers[HttpHeaders .accessControlAllowMethodsHeader] =
121+ 'GET, POST, PUT, DELETE, OPTIONS' ;
122+ headers[HttpHeaders .accessControlAllowHeadersHeader] =
123+ 'Origin, Content-Type, Authorization' ;
124+ }
125+ }
126+
127+ return Response .json (
128+ statusCode: statusCode,
129+ body: {'error' : {'code' : errorCode, 'message' : exception.message}},
130+ headers: headers,
131+ );
132+ }
0 commit comments