corteq 0.1.0

Enterprise-grade multi-tenant SaaS framework for Rust with security-first design
Documentation
//! Error types for Corteq framework

use actix_web::{error::ResponseError, http::StatusCode, HttpResponse};
use thiserror::Error;

/// Result type alias for Corteq operations
pub type Result<T> = std::result::Result<T, CorteqError>;

/// Core error types for the Corteq framework
#[derive(Debug, Error)]
pub enum CorteqError {
    /// Tenant context is missing or invalid
    #[error("Invalid or missing tenant context: {0}")]
    InvalidTenantContext(String),

    /// Authentication failed
    #[error("Authentication failed: {0}")]
    AuthenticationFailed(String),

    /// Authorization failed (permission denied)
    #[error("Permission denied: {0}")]
    AuthorizationFailed(String),

    /// Database operation failed
    #[error("Database error: {0}")]
    DatabaseError(#[from] sqlx::Error),

    /// JWT token error
    #[error("JWT error: {0}")]
    JwtError(#[from] jsonwebtoken::errors::Error),

    /// Encryption/decryption error
    #[error("Encryption error: {0}")]
    EncryptionError(String),

    /// Validation error
    #[error("Validation error: {0}")]
    ValidationError(String),

    /// Configuration error
    #[error("Configuration error: {0}")]
    ConfigError(String),

    /// Internal server error
    #[error("Internal error: {0}")]
    InternalError(String),
}

/// Implement Actix Web's ResponseError trait for automatic HTTP error conversion
impl ResponseError for CorteqError {
    fn status_code(&self) -> StatusCode {
        match self {
            Self::InvalidTenantContext(_) => StatusCode::BAD_REQUEST,
            Self::AuthenticationFailed(_) => StatusCode::UNAUTHORIZED,
            Self::AuthorizationFailed(_) => StatusCode::FORBIDDEN,
            Self::ValidationError(_) => StatusCode::UNPROCESSABLE_ENTITY,
            Self::DatabaseError(_) => StatusCode::INTERNAL_SERVER_ERROR,
            Self::JwtError(_) => StatusCode::UNAUTHORIZED,
            Self::EncryptionError(_) => StatusCode::INTERNAL_SERVER_ERROR,
            Self::ConfigError(_) => StatusCode::INTERNAL_SERVER_ERROR,
            Self::InternalError(_) => StatusCode::INTERNAL_SERVER_ERROR,
        }
    }

    fn error_response(&self) -> HttpResponse {
        HttpResponse::build(self.status_code()).json(serde_json::json!({
            "error": self.to_string(),
            "type": self.error_type(),
        }))
    }
}

impl CorteqError {
    /// Get a type string for the error (for API responses)
    fn error_type(&self) -> &str {
        match self {
            Self::InvalidTenantContext(_) => "invalid_tenant_context",
            Self::AuthenticationFailed(_) => "authentication_failed",
            Self::AuthorizationFailed(_) => "authorization_failed",
            Self::ValidationError(_) => "validation_error",
            Self::DatabaseError(_) => "database_error",
            Self::JwtError(_) => "jwt_error",
            Self::EncryptionError(_) => "encryption_error",
            Self::ConfigError(_) => "config_error",
            Self::InternalError(_) => "internal_error",
        }
    }
}