reqkey 0.1.0

Official Rust SDK for ReqKey API key validation, credit metering, and analytics
Documentation
use serde_json::Value;
use thiserror::Error;

/// A ReqKey operation, used in transport errors and middleware notifications.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Operation {
    /// Consumer-key validation and credit deduction.
    Validate,
    /// Request analytics ingestion.
    Ingest,
}

impl std::fmt::Display for Operation {
    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        formatter.write_str(match self {
            Self::Validate => "validate",
            Self::Ingest => "ingest",
        })
    }
}

/// Errors returned by the ReqKey SDK.
#[derive(Clone, Debug, Error)]
#[non_exhaustive]
pub enum Error {
    /// A local SDK configuration or method argument is invalid.
    #[error("invalid ReqKey configuration: {0}")]
    Configuration(String),

    /// A ReqKey request exceeded the configured timeout.
    #[error("ReqKey {operation} request timed out")]
    Timeout {
        /// Operation that timed out.
        operation: Operation,
    },

    /// ReqKey could not be reached.
    #[error("could not reach ReqKey during {operation}: {message}")]
    Transport {
        /// Operation that failed.
        operation: Operation,
        /// Provider-neutral transport message.
        message: String,
    },

    /// The project credential was rejected with HTTP 401.
    #[error("ReqKey rejected the project credential: {message}")]
    Authentication {
        /// HTTP status code, currently always 401.
        status: u16,
        /// Error returned by ReqKey.
        message: String,
        /// Parsed response body when available.
        body: Option<Value>,
    },

    /// ReqKey returned a response that was not a validation decision.
    #[error("ReqKey API returned HTTP {status}: {message}")]
    Api {
        /// HTTP status code.
        status: u16,
        /// Error returned by ReqKey.
        message: String,
        /// Parsed response body when available.
        body: Option<Value>,
    },
}

impl Error {
    /// Return the HTTP status attached to an API error, if any.
    pub fn status_code(&self) -> Option<u16> {
        match self {
            Self::Authentication { status, .. } | Self::Api { status, .. } => Some(*status),
            _ => None,
        }
    }

    /// Return true for timeout or connection/service transport failures.
    pub fn is_unavailable(&self) -> bool {
        matches!(
            self,
            Self::Timeout { .. } | Self::Transport { .. } | Self::Api { .. }
        )
    }
}

/// Result alias used throughout the SDK.
pub type Result<T> = std::result::Result<T, Error>;