crypto-pay-api 0.2.1

A Rust client library for Crypto Pay API provided by Telegram CryptoBot
Documentation
use thiserror::Error;

#[derive(Error, Debug)]
pub enum CryptoBotError {
    #[error("Invalid header name: {0}")]
    InvalidHeaderName(#[from] reqwest::header::InvalidHeaderName),

    #[error("Invalid header value: {0}")]
    InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),

    #[error("HTTP client error: {0}")]
    HttpError(#[from] reqwest::Error),

    #[error("API error: {code} - {message}")]
    ApiError {
        code: i32,
        message: String,
        details: Option<serde_json::Value>,
    },

    #[error("Validation error: {kind} - {message}")]
    ValidationError {
        kind: ValidationErrorKind,
        message: String,
        field: Option<String>,
    },

    #[error("Webhook error: {kind} - {message}")]
    WebhookError { kind: WebhookErrorKind, message: String },

    #[error("No result returned from API")]
    NoResult,
}

#[derive(Debug, PartialEq)]
pub enum ValidationErrorKind {
    Format,
    Range,
    Currency,
    Missing,
    Invalid,
}

#[derive(Debug)]
pub enum WebhookErrorKind {
    InvalidSignature,
    InvalidPayload,
    DeserializationError,
    Expired,
}

impl std::fmt::Display for ValidationErrorKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{self:?}")
    }
}

impl std::fmt::Display for WebhookErrorKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{self:?}")
    }
}

pub type CryptoBotResult<T> = std::result::Result<T, CryptoBotError>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_validation_error_kind_display() {
        let test_cases = vec![
            (ValidationErrorKind::Range, "Range"),
            (ValidationErrorKind::Format, "Format"),
            (ValidationErrorKind::Missing, "Missing"),
            (ValidationErrorKind::Invalid, "Invalid"),
            (ValidationErrorKind::Currency, "Currency"),
        ];

        for (kind, expected) in test_cases {
            assert_eq!(kind.to_string(), expected);
        }
    }

    #[test]
    fn test_webhook_error_kind_display() {
        let test_cases = vec![
            (WebhookErrorKind::InvalidSignature, "InvalidSignature"),
            (WebhookErrorKind::InvalidPayload, "InvalidPayload"),
            (WebhookErrorKind::DeserializationError, "DeserializationError"),
            (WebhookErrorKind::Expired, "Expired"),
        ];

        for (kind, expected) in test_cases {
            assert_eq!(kind.to_string(), expected);
        }
    }

    #[test]
    fn test_validation_error_formatting() {
        let error = CryptoBotError::ValidationError {
            kind: ValidationErrorKind::Range,
            message: "Value out of range".to_string(),
            field: Some("amount".to_string()),
        };

        assert_eq!(error.to_string(), "Validation error: Range - Value out of range");
    }

    #[test]
    fn test_webhook_error_formatting() {
        let error = CryptoBotError::WebhookError {
            kind: WebhookErrorKind::InvalidSignature,
            message: "Invalid signature".to_string(),
        };

        assert_eq!(error.to_string(), "Webhook error: InvalidSignature - Invalid signature");
    }
}