backstage-client 0.1.4

A Rust client library for interacting with the Backstage Catalog API. Provides type-safe access to Backstage entities with async support, filtering, and comprehensive error handling.
Documentation
use reqwest::Error as ReqwestError;
use serde_json::Error as SerdeJsonError;
use std::fmt;

/// Error types that can occur when using the Backstage client.
#[derive(Debug)]
pub enum ClientError {
    /// HTTP request failed
    Http(ReqwestError),
    /// JSON serialization/deserialization failed
    Json(SerdeJsonError),
    /// Invalid URL provided
    InvalidUrl(String),
    /// Authentication failed
    Authentication(String),
    /// API returned an error response
    ApiError { status: u16, message: String },
    /// Invalid filter parameters
    InvalidFilter(String),
    /// Network timeout
    Timeout,
    /// Generic client error
    Other(String),
}

impl fmt::Display for ClientError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ClientError::Http(err) => write!(f, "HTTP request failed: {}", err),
            ClientError::Json(err) => write!(f, "JSON parsing failed: {}", err),
            ClientError::InvalidUrl(url) => write!(f, "Invalid URL: {}", url),
            ClientError::Authentication(msg) => write!(f, "Authentication failed: {}", msg),
            ClientError::ApiError { status, message } => {
                write!(f, "API error (status {}): {}", status, message)
            }
            ClientError::InvalidFilter(msg) => write!(f, "Invalid filter: {}", msg),
            ClientError::Timeout => write!(f, "Request timed out"),
            ClientError::Other(msg) => write!(f, "Client error: {}", msg),
        }
    }
}

impl std::error::Error for ClientError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            ClientError::Http(err) => Some(err),
            ClientError::Json(err) => Some(err),
            _ => None,
        }
    }
}

impl From<ReqwestError> for ClientError {
    fn from(err: ReqwestError) -> ClientError {
        if err.is_timeout() {
            ClientError::Timeout
        } else if err.is_status() {
            if let Some(status) = err.status() {
                ClientError::ApiError {
                    status: status.as_u16(),
                    message: err.to_string(),
                }
            } else {
                ClientError::Http(err)
            }
        } else {
            ClientError::Http(err)
        }
    }
}

impl From<SerdeJsonError> for ClientError {
    fn from(err: SerdeJsonError) -> ClientError {
        ClientError::Json(err)
    }
}

impl From<url::ParseError> for ClientError {
    fn from(err: url::ParseError) -> ClientError {
        ClientError::InvalidUrl(err.to_string())
    }
}

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