@@ -65,11 +65,33 @@ struct InputData {
6565 format : Option < FileFormat > ,
6666}
6767
68+ /// Typed error categories for API error responses.
69+ ///
70+ /// Serialized as `snake_case` strings in JSON to maintain backwards compatibility.
71+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Serialize ) ]
72+ #[ serde( rename_all = "snake_case" ) ]
73+ pub enum ErrorType {
74+ FieldLimitExceeded ,
75+ FileTooLarge ,
76+ TextTooLarge ,
77+ InternalError ,
78+ InvalidMatchId ,
79+ FilenameTooLong ,
80+ InvalidFilename ,
81+ FormatMismatch ,
82+ InvalidContent ,
83+ ValidationFailed ,
84+ MissingInput ,
85+ FormatDetectionFailed ,
86+ ParseFailed ,
87+ BinaryParseFailed ,
88+ }
89+
6890/// Enhanced error response
6991#[ derive( Serialize ) ]
7092pub struct ErrorResponse {
7193 pub error : String ,
72- pub error_type : String ,
94+ pub error_type : ErrorType ,
7395 pub details : Option < String > ,
7496}
7597
@@ -100,18 +122,18 @@ struct DetailedQueryParams {
100122/// Create a safe error response that prevents information disclosure
101123/// while logging detailed errors server-side for debugging
102124pub fn create_safe_error_response (
103- error_type : & str ,
125+ error_type : ErrorType ,
104126 user_message : & str ,
105127 internal_error : Option < & str > ,
106128) -> ErrorResponse {
107129 // Log detailed error server-side for debugging (not exposed to client)
108130 if let Some ( internal_msg) = internal_error {
109- tracing:: error!( "Internal error ({}): {}" , error_type, internal_msg) ;
131+ tracing:: error!( "Internal error ({:? }): {}" , error_type, internal_msg) ;
110132 }
111133
112134 ErrorResponse {
113135 error : user_message. to_string ( ) ,
114- error_type : error_type . to_string ( ) ,
136+ error_type,
115137 details : None , // Never expose internal details to prevent information disclosure
116138 }
117139}
@@ -489,7 +511,7 @@ async fn handle_detailed_response(
489511 return (
490512 StatusCode :: BAD_REQUEST ,
491513 Json ( create_safe_error_response (
492- "invalid_match_id" ,
514+ ErrorType :: InvalidMatchId ,
493515 "Invalid match ID specified" ,
494516 Some ( "Match index out of bounds" ) ,
495517 ) ) ,
@@ -807,7 +829,7 @@ async fn extract_request_data(
807829 StatusCode :: BAD_REQUEST ,
808830 Json ( ErrorResponse {
809831 error : "Too many form fields" . to_string ( ) ,
810- error_type : "field_limit_exceeded" . to_string ( ) ,
832+ error_type : ErrorType :: FieldLimitExceeded ,
811833 details : None , // No internal details for security
812834 } ) ,
813835 )
@@ -851,7 +873,7 @@ async fn extract_request_data(
851873 StatusCode :: PAYLOAD_TOO_LARGE ,
852874 Json ( ErrorResponse {
853875 error : "File size exceeds limit" . to_string ( ) ,
854- error_type : "file_too_large" . to_string ( ) ,
876+ error_type : ErrorType :: FileTooLarge ,
855877 details : None ,
856878 } ) ,
857879 )
@@ -877,7 +899,7 @@ async fn extract_request_data(
877899 return Err ( (
878900 StatusCode :: BAD_REQUEST ,
879901 Json ( create_safe_error_response (
880- "filename_too_long" ,
902+ ErrorType :: FilenameTooLong ,
881903 "Filename exceeds maximum length limit" ,
882904 Some ( "Filename validation failed due to length constraints" )
883905 ) ) ,
@@ -887,7 +909,7 @@ async fn extract_request_data(
887909 return Err ( (
888910 StatusCode :: BAD_REQUEST ,
889911 Json ( create_safe_error_response (
890- "invalid_filename" ,
912+ ErrorType :: InvalidFilename ,
891913 "Filename contains invalid or dangerous characters" ,
892914 Some ( "Filename validation failed due to invalid characters" )
893915 ) ) ,
@@ -897,7 +919,7 @@ async fn extract_request_data(
897919 return Err ( (
898920 StatusCode :: BAD_REQUEST ,
899921 Json ( create_safe_error_response (
900- "format_mismatch" ,
922+ ErrorType :: FormatMismatch ,
901923 "File content does not match the expected format based on filename" ,
902924 Some ( "Format validation failed" )
903925 ) ) ,
@@ -907,7 +929,7 @@ async fn extract_request_data(
907929 return Err ( (
908930 StatusCode :: BAD_REQUEST ,
909931 Json ( create_safe_error_response (
910- "invalid_content" ,
932+ ErrorType :: InvalidContent ,
911933 "File content appears malformed or corrupted" ,
912934 None ,
913935 ) ) ,
@@ -918,7 +940,7 @@ async fn extract_request_data(
918940 return Err ( (
919941 StatusCode :: BAD_REQUEST ,
920942 Json ( create_safe_error_response (
921- "validation_failed" ,
943+ ErrorType :: ValidationFailed ,
922944 "File validation failed" ,
923945 None ,
924946 ) ) ,
@@ -938,7 +960,7 @@ async fn extract_request_data(
938960 StatusCode :: PAYLOAD_TOO_LARGE ,
939961 Json ( ErrorResponse {
940962 error : "Text field size exceeds limit" . to_string ( ) ,
941- error_type : "text_too_large" . to_string ( ) ,
963+ error_type : ErrorType :: TextTooLarge ,
942964 details : None ,
943965 } ) ,
944966 )
@@ -997,7 +1019,7 @@ async fn extract_request_data(
9971019 return Err ( (
9981020 StatusCode :: BAD_REQUEST ,
9991021 Json ( create_safe_error_response (
1000- "missing_input" ,
1022+ ErrorType :: MissingInput ,
10011023 error_msg,
10021024 None , // Never include details for consistency
10031025 ) ) ,
@@ -1036,7 +1058,7 @@ fn parse_input_data(
10361058 (
10371059 StatusCode :: BAD_REQUEST ,
10381060 Json ( create_safe_error_response (
1039- "format_detection_failed" ,
1061+ ErrorType :: FormatDetectionFailed ,
10401062 "Unable to detect file format. Please check the file type and try again." ,
10411063 Some ( "Format detection failed during parsing" ) ,
10421064 ) ) ,
@@ -1050,7 +1072,7 @@ fn parse_input_data(
10501072 Err ( _) => Err ( Box :: new ( (
10511073 StatusCode :: BAD_REQUEST ,
10521074 Json ( create_safe_error_response (
1053- "parse_failed" ,
1075+ ErrorType :: ParseFailed ,
10541076 "Unable to process file content. Please check the file format and try again." ,
10551077 Some ( "File parsing failed during content processing" ) ,
10561078 ) ) ,
@@ -1066,7 +1088,7 @@ fn parse_input_data(
10661088 Err ( _) => Err ( Box :: new ( (
10671089 StatusCode :: BAD_REQUEST ,
10681090 Json ( create_safe_error_response (
1069- "binary_parse_failed" ,
1091+ ErrorType :: BinaryParseFailed ,
10701092 "Unable to process binary file. Please verify the file format and try again." ,
10711093 Some ( "Binary file parsing failed during processing" ) ,
10721094 ) ) ,
@@ -1079,7 +1101,7 @@ fn parse_input_data(
10791101 StatusCode :: INTERNAL_SERVER_ERROR ,
10801102 Json ( ErrorResponse {
10811103 error : "Internal error: no input data" . to_string ( ) ,
1082- error_type : "internal_error" . to_string ( ) ,
1104+ error_type : ErrorType :: InternalError ,
10831105 details : None ,
10841106 } ) ,
10851107 )
0 commit comments