openzeppelin_relayer/models/error/
api.rs

1use actix_web::{HttpResponse, ResponseError};
2use eyre::Report;
3use thiserror::Error;
4
5use crate::models::ApiResponse;
6
7#[derive(Error, Debug)]
8pub enum ApiError {
9    #[error("Internal Server Error: {0}")]
10    InternalEyreError(#[from] Report),
11
12    #[error("Internal Server Error: {0}")]
13    InternalError(String),
14
15    #[error("Not Found: {0}")]
16    NotFound(String),
17
18    #[error("Bad Request: {0}")]
19    BadRequest(String),
20
21    #[error("Unauthorized: {0}")]
22    Unauthorized(String),
23
24    #[error("Not Supported: {0}")]
25    NotSupported(String),
26
27    #[error("Forbidden: {0}")]
28    ForbiddenError(String),
29}
30
31impl ResponseError for ApiError {
32    fn error_response(&self) -> HttpResponse {
33        match self {
34            ApiError::InternalError(msg) => {
35                HttpResponse::InternalServerError().json(ApiResponse::<()>::error(msg))
36            }
37            ApiError::NotFound(msg) => HttpResponse::NotFound().json(ApiResponse::<()>::error(msg)),
38            ApiError::BadRequest(msg) => {
39                HttpResponse::BadRequest().json(ApiResponse::<()>::error(msg))
40            }
41            ApiError::Unauthorized(msg) => {
42                HttpResponse::Unauthorized().json(ApiResponse::<()>::error(msg))
43            }
44            ApiError::NotSupported(msg) => {
45                HttpResponse::NotImplemented().json(ApiResponse::<()>::error(msg))
46            }
47            ApiError::InternalEyreError(msg) => {
48                HttpResponse::InternalServerError().json(ApiResponse::<()>::error(msg.to_string()))
49            }
50            ApiError::ForbiddenError(msg) => {
51                HttpResponse::Forbidden().json(ApiResponse::<()>::error(msg))
52            }
53        }
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use actix_web::http::StatusCode;
61
62    #[test]
63    fn test_api_error_variants() {
64        // Test error message formatting for each variant
65        let internal_error = ApiError::InternalError("Database connection failed".to_string());
66        assert_eq!(
67            internal_error.to_string(),
68            "Internal Server Error: Database connection failed"
69        );
70
71        let not_found = ApiError::NotFound("User not found".to_string());
72        assert_eq!(not_found.to_string(), "Not Found: User not found");
73
74        let bad_request = ApiError::BadRequest("Invalid input".to_string());
75        assert_eq!(bad_request.to_string(), "Bad Request: Invalid input");
76
77        let unauthorized = ApiError::Unauthorized("Invalid token".to_string());
78        assert_eq!(unauthorized.to_string(), "Unauthorized: Invalid token");
79
80        let not_supported = ApiError::NotSupported("Feature not available".to_string());
81        assert_eq!(
82            not_supported.to_string(),
83            "Not Supported: Feature not available"
84        );
85
86        let forbidden = ApiError::ForbiddenError("Access denied".to_string());
87        assert_eq!(forbidden.to_string(), "Forbidden: Access denied");
88
89        // Test Report conversion
90        let report = Report::msg("Something went wrong");
91        let internal_eyre_error = ApiError::InternalEyreError(report);
92        assert!(internal_eyre_error
93            .to_string()
94            .starts_with("Internal Server Error:"));
95    }
96
97    #[test]
98    fn test_response_error_implementation() {
99        // Test that each error variant returns the correct status code and response
100        let internal_error = ApiError::InternalError("Server error".to_string());
101        let response = internal_error.error_response();
102        assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
103
104        let not_found = ApiError::NotFound("Resource not found".to_string());
105        let response = not_found.error_response();
106        assert_eq!(response.status(), StatusCode::NOT_FOUND);
107
108        let bad_request = ApiError::BadRequest("Invalid parameters".to_string());
109        let response = bad_request.error_response();
110        assert_eq!(response.status(), StatusCode::BAD_REQUEST);
111
112        let unauthorized = ApiError::Unauthorized("Authentication required".to_string());
113        let response = unauthorized.error_response();
114        assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
115
116        let not_supported = ApiError::NotSupported("Not implemented".to_string());
117        let response = not_supported.error_response();
118        assert_eq!(response.status(), StatusCode::NOT_IMPLEMENTED);
119
120        let forbidden = ApiError::ForbiddenError("Permission denied".to_string());
121        let response = forbidden.error_response();
122        assert_eq!(response.status(), StatusCode::FORBIDDEN);
123
124        let report = Report::msg("Internal error");
125        let internal_eyre_error = ApiError::InternalEyreError(report);
126        let response = internal_eyre_error.error_response();
127        assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
128    }
129}