apikeys_rs/axum_layer/
errors.rs1use 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}