@@ -19,54 +19,38 @@ Middleware errorHandler() {
19
19
} on HtHttpException catch (e, stackTrace) {
20
20
// Handle specific HtHttpExceptions from the client/repository layers
21
21
final statusCode = _mapExceptionToStatusCode (e);
22
- final errorCode = _mapExceptionToCodeString (e);
23
22
print ('HtHttpException Caught: $e \n $stackTrace ' ); // Log for debugging
24
- return Response . json (
23
+ return _jsonErrorResponse (
25
24
statusCode: statusCode,
26
- body: {
27
- 'error' : {'code' : errorCode, 'message' : e.message},
28
- },
25
+ exception: e,
26
+ context: context,
29
27
);
30
28
} on CheckedFromJsonException catch (e, stackTrace) {
31
29
// Handle json_serializable validation errors. These are client errors.
32
30
final field = e.key ?? 'unknown' ;
33
31
final message = 'Invalid request body: Field "$field " has an '
34
32
'invalid value or is missing. ${e .message }' ;
35
33
print ('CheckedFromJsonException Caught: $e \n $stackTrace ' );
36
- return Response . json (
34
+ return _jsonErrorResponse (
37
35
statusCode: HttpStatus .badRequest, // 400
38
- body: {
39
- 'error' : {
40
- 'code' : 'invalidField' ,
41
- 'message' : message,
42
- },
43
- },
36
+ exception: InvalidInputException (message),
37
+ context: context,
44
38
);
45
39
} on FormatException catch (e, stackTrace) {
46
40
// Handle data format/parsing errors (often indicates bad client input)
47
41
print ('FormatException Caught: $e \n $stackTrace ' ); // Log for debugging
48
- return Response . json (
42
+ return _jsonErrorResponse (
49
43
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,
56
46
);
57
47
} catch (e, stackTrace) {
58
48
// Handle any other unexpected errors
59
49
print ('Unhandled Exception Caught: $e \n $stackTrace ' );
60
- return Response . json (
50
+ return _jsonErrorResponse (
61
51
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,
70
54
);
71
55
}
72
56
};
@@ -108,3 +92,41 @@ String _mapExceptionToCodeString(HtHttpException exception) {
108
92
_ => 'unknownError' , // Default
109
93
};
110
94
}
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