apikeys_rs/axum_layer/
errors.rs

1use std::fmt;
2
3use axum::{
4    body::Body,
5    response::{IntoResponse, Response},
6    Json,
7};
8use http::StatusCode;
9use serde::Serialize;
10
11use crate::errors::{ApiKeyLimiterError, ApiKeyStorageError};
12
13#[derive(Debug)]
14pub enum ApiKeyLayerError {
15    MissingApiKey,
16    InvalidApiKey,
17    ApiKeyNotFound,
18    DomainNotAllowed,
19    LimiterError(ApiKeyLimiterError),
20    StorageError(ApiKeyStorageError),
21    UnexpectedError,
22}
23
24impl fmt::Display for ApiKeyLayerError {
25    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26        match self {
27            ApiKeyLayerError::MissingApiKey => write!(f, "x-api-key header is not set"),
28            ApiKeyLayerError::InvalidApiKey => write!(f, "The provided API key is not valid"),
29            ApiKeyLayerError::ApiKeyNotFound => write!(f, "The provided API key was not found"),
30            ApiKeyLayerError::DomainNotAllowed => {
31                write!(f, "The provided API key is not allowed for this domain")
32            }
33            ApiKeyLayerError::LimiterError(e) => write!(f, "Limiter error: {}", e),
34            ApiKeyLayerError::UnexpectedError => write!(f, "Unexpected error"),
35            ApiKeyLayerError::StorageError(e) => write!(f, "Storage error: {}", e),
36        }
37    }
38}
39
40impl ApiKeyLayerError {
41    pub fn to_message_type(&self) -> String {
42        match self {
43            ApiKeyLayerError::MissingApiKey => "MissingApiKey".to_string(),
44            ApiKeyLayerError::InvalidApiKey => "InvalidApiKey".to_string(),
45            ApiKeyLayerError::ApiKeyNotFound => "ApiKeyNotFound".to_string(),
46            ApiKeyLayerError::DomainNotAllowed => "DomainNotAllowed".to_string(),
47            ApiKeyLayerError::LimiterError(e) => e.to_message_type(),
48            ApiKeyLayerError::UnexpectedError => "UnexpectedError".to_string(),
49            ApiKeyLayerError::StorageError(e) => e.to_message_type(),
50        }
51    }
52}
53
54impl std::error::Error for ApiKeyLayerError {}
55
56impl From<ApiKeyLayerError> for ApiKeyErrorResponse {
57    fn from(error: ApiKeyLayerError) -> Self {
58        ApiKeyErrorResponse { message: error.to_string(), _type: error.to_message_type() }
59    }
60}
61
62impl IntoResponse for ApiKeyLayerError {
63    fn into_response(self) -> Response<Body> {
64        match self {
65            ApiKeyLayerError::MissingApiKey => {
66                (StatusCode::UNAUTHORIZED, Json::<ApiKeyErrorResponse>(self.into())).into_response()
67            }
68            ApiKeyLayerError::InvalidApiKey => {
69                (StatusCode::UNAUTHORIZED, Json::<ApiKeyErrorResponse>(self.into())).into_response()
70            }
71            ApiKeyLayerError::ApiKeyNotFound => {
72                (StatusCode::UNAUTHORIZED, Json::<ApiKeyErrorResponse>(self.into())).into_response()
73            }
74            ApiKeyLayerError::DomainNotAllowed => {
75                (StatusCode::UNAUTHORIZED, Json::<ApiKeyErrorResponse>(self.into())).into_response()
76            }
77            ApiKeyLayerError::LimiterError(e) => (
78                StatusCode::UNAUTHORIZED,
79                Json::<ApiKeyErrorResponse>(ApiKeyErrorResponse { message: e.to_string(), _type: e.to_message_type() }),
80            )
81                .into_response(),
82            ApiKeyLayerError::UnexpectedError => {
83                (StatusCode::INTERNAL_SERVER_ERROR, Json::<ApiKeyErrorResponse>(self.into())).into_response()
84            }
85            ApiKeyLayerError::StorageError(e) => (
86                StatusCode::INTERNAL_SERVER_ERROR,
87                Json::<ApiKeyErrorResponse>(ApiKeyErrorResponse { message: e.to_string(), _type: e.to_message_type() }),
88            )
89                .into_response(),
90        }
91    }
92}
93
94#[derive(Debug, Serialize)]
95#[serde(rename_all = "camelCase")]
96struct ApiKeyErrorResponse {
97    message: String,
98    #[serde(rename = "type")]
99    _type: String,
100}