Skip to main content

soaprs_http/
error_mapping.rs

1//! Default mapping from stable application errors to HTTP status codes.
2
3use http::StatusCode;
4use soaprs_core::{SoapError, SoapErrorKind};
5
6/// Returns the default HTTP status for a stable soaprs error category.
7///
8/// Framework adapters may override this mapping at their composition root.
9pub const fn default_error_status(error: &SoapError) -> StatusCode {
10    match error.kind() {
11        SoapErrorKind::NotFound => StatusCode::NOT_FOUND,
12        SoapErrorKind::Validation | SoapErrorKind::Domain => StatusCode::UNPROCESSABLE_ENTITY,
13        SoapErrorKind::Conflict => StatusCode::CONFLICT,
14        SoapErrorKind::Unauthorized => StatusCode::UNAUTHORIZED,
15        SoapErrorKind::Forbidden => StatusCode::FORBIDDEN,
16        SoapErrorKind::Unsupported => StatusCode::NOT_IMPLEMENTED,
17        SoapErrorKind::Timeout => StatusCode::GATEWAY_TIMEOUT,
18        SoapErrorKind::Unavailable => StatusCode::SERVICE_UNAVAILABLE,
19        SoapErrorKind::Infrastructure => StatusCode::INTERNAL_SERVER_ERROR,
20    }
21}
22
23#[cfg(test)]
24mod tests {
25    use http::StatusCode;
26    use soaprs_core::SoapError;
27
28    use super::default_error_status;
29
30    #[test]
31    fn distinguishes_authentication_and_authorization() {
32        assert_eq!(
33            default_error_status(&SoapError::unauthorized()),
34            StatusCode::UNAUTHORIZED
35        );
36        assert_eq!(
37            default_error_status(&SoapError::forbidden()),
38            StatusCode::FORBIDDEN
39        );
40    }
41
42    #[test]
43    fn maps_stable_error_categories_to_default_statuses() {
44        let cases = [
45            (SoapError::not_found("user"), StatusCode::NOT_FOUND),
46            (
47                SoapError::validation("invalid email"),
48                StatusCode::UNPROCESSABLE_ENTITY,
49            ),
50            (
51                SoapError::domain("account is closed"),
52                StatusCode::UNPROCESSABLE_ENTITY,
53            ),
54            (SoapError::conflict("email exists"), StatusCode::CONFLICT),
55            (
56                SoapError::unsupported("full-text search"),
57                StatusCode::NOT_IMPLEMENTED,
58            ),
59            (
60                SoapError::timeout("database query"),
61                StatusCode::GATEWAY_TIMEOUT,
62            ),
63            (
64                SoapError::unavailable("database"),
65                StatusCode::SERVICE_UNAVAILABLE,
66            ),
67            (
68                SoapError::infrastructure("database operation"),
69                StatusCode::INTERNAL_SERVER_ERROR,
70            ),
71        ];
72
73        for (error, expected) in cases {
74            assert_eq!(default_error_status(&error), expected);
75        }
76    }
77}