use actix_web::{http::StatusCode, HttpResponse, ResponseError};
use derive_more::{Display, Error};
#[derive(Debug, Display, Error)]
pub enum ApiKeyError {
#[display("Unauthorized: API key not provided")]
Missing,
#[display("Unauthorized: invalid API key format")]
InvalidFormat,
#[display("Unauthorized: invalid API key")]
Invalid,
#[display("Unauthorized: API key has expired")]
Expired,
#[display("Unauthorized: API key is disabled")]
Disabled,
#[display("Forbidden: insufficient API key permissions")]
InsufficientPermissions,
#[display("Too Many Requests: rate limit exceeded for this API key")]
RateLimitExceeded,
}
impl ResponseError for ApiKeyError {
fn status_code(&self) -> StatusCode {
match self {
ApiKeyError::Missing
| ApiKeyError::InvalidFormat
| ApiKeyError::Invalid
| ApiKeyError::Expired
| ApiKeyError::Disabled => StatusCode::UNAUTHORIZED,
ApiKeyError::InsufficientPermissions => StatusCode::FORBIDDEN,
ApiKeyError::RateLimitExceeded => StatusCode::TOO_MANY_REQUESTS,
}
}
fn error_response(&self) -> HttpResponse {
let status = self.status_code();
let error = status.canonical_reason().unwrap_or("Error");
let message = self.to_string();
let body = format!(r#"{{"error":"{}","message":"{}"}}"#, error, message);
HttpResponse::build(status)
.content_type("application/json")
.body(body)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_missing_status() {
let err = ApiKeyError::Missing;
assert_eq!(err.status_code(), StatusCode::UNAUTHORIZED);
}
#[test]
fn test_invalid_status() {
let err = ApiKeyError::Invalid;
assert_eq!(err.status_code(), StatusCode::UNAUTHORIZED);
}
#[test]
fn test_insufficient_permissions_status() {
let err = ApiKeyError::InsufficientPermissions;
assert_eq!(err.status_code(), StatusCode::FORBIDDEN);
}
#[test]
fn test_rate_limit_status() {
let err = ApiKeyError::RateLimitExceeded;
assert_eq!(err.status_code(), StatusCode::TOO_MANY_REQUESTS);
}
}