openzeppelin_relayer/models/error/
api.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use actix_web::{HttpResponse, ResponseError};
use eyre::Report;
use thiserror::Error;

use crate::models::ApiResponse;

#[derive(Error, Debug)]
pub enum ApiError {
    #[error("Internal Server Error: {0}")]
    InternalEyreError(#[from] Report),

    #[error("Internal Server Error: {0}")]
    InternalError(String),

    #[error("Not Found: {0}")]
    NotFound(String),

    #[error("Bad Request: {0}")]
    BadRequest(String),

    #[error("Unauthorized: {0}")]
    Unauthorized(String),

    #[error("Not Supported: {0}")]
    NotSupported(String),

    #[error("Forbidden: {0}")]
    ForbiddenError(String),
}

impl ResponseError for ApiError {
    fn error_response(&self) -> HttpResponse {
        match self {
            ApiError::InternalError(msg) => {
                HttpResponse::InternalServerError().json(ApiResponse::<()>::error(msg))
            }
            ApiError::NotFound(msg) => HttpResponse::NotFound().json(ApiResponse::<()>::error(msg)),
            ApiError::BadRequest(msg) => {
                HttpResponse::BadRequest().json(ApiResponse::<()>::error(msg))
            }
            ApiError::Unauthorized(msg) => {
                HttpResponse::Unauthorized().json(ApiResponse::<()>::error(msg))
            }
            ApiError::NotSupported(msg) => {
                HttpResponse::NotImplemented().json(ApiResponse::<()>::error(msg))
            }
            ApiError::InternalEyreError(msg) => {
                HttpResponse::InternalServerError().json(ApiResponse::<()>::error(msg.to_string()))
            }
            ApiError::ForbiddenError(msg) => {
                HttpResponse::Forbidden().json(ApiResponse::<()>::error(msg))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use actix_web::http::StatusCode;

    #[test]
    fn test_api_error_variants() {
        // Test error message formatting for each variant
        let internal_error = ApiError::InternalError("Database connection failed".to_string());
        assert_eq!(
            internal_error.to_string(),
            "Internal Server Error: Database connection failed"
        );

        let not_found = ApiError::NotFound("User not found".to_string());
        assert_eq!(not_found.to_string(), "Not Found: User not found");

        let bad_request = ApiError::BadRequest("Invalid input".to_string());
        assert_eq!(bad_request.to_string(), "Bad Request: Invalid input");

        let unauthorized = ApiError::Unauthorized("Invalid token".to_string());
        assert_eq!(unauthorized.to_string(), "Unauthorized: Invalid token");

        let not_supported = ApiError::NotSupported("Feature not available".to_string());
        assert_eq!(
            not_supported.to_string(),
            "Not Supported: Feature not available"
        );

        let forbidden = ApiError::ForbiddenError("Access denied".to_string());
        assert_eq!(forbidden.to_string(), "Forbidden: Access denied");

        // Test Report conversion
        let report = Report::msg("Something went wrong");
        let internal_eyre_error = ApiError::InternalEyreError(report);
        assert!(internal_eyre_error
            .to_string()
            .starts_with("Internal Server Error:"));
    }

    #[test]
    fn test_response_error_implementation() {
        // Test that each error variant returns the correct status code and response
        let internal_error = ApiError::InternalError("Server error".to_string());
        let response = internal_error.error_response();
        assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);

        let not_found = ApiError::NotFound("Resource not found".to_string());
        let response = not_found.error_response();
        assert_eq!(response.status(), StatusCode::NOT_FOUND);

        let bad_request = ApiError::BadRequest("Invalid parameters".to_string());
        let response = bad_request.error_response();
        assert_eq!(response.status(), StatusCode::BAD_REQUEST);

        let unauthorized = ApiError::Unauthorized("Authentication required".to_string());
        let response = unauthorized.error_response();
        assert_eq!(response.status(), StatusCode::UNAUTHORIZED);

        let not_supported = ApiError::NotSupported("Not implemented".to_string());
        let response = not_supported.error_response();
        assert_eq!(response.status(), StatusCode::NOT_IMPLEMENTED);

        let forbidden = ApiError::ForbiddenError("Permission denied".to_string());
        let response = forbidden.error_response();
        assert_eq!(response.status(), StatusCode::FORBIDDEN);

        let report = Report::msg("Internal error");
        let internal_eyre_error = ApiError::InternalEyreError(report);
        let response = internal_eyre_error.error_response();
        assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }
}