parcelwing 0.1.0

Official Rust SDK for the Parcel Wing API.
Documentation
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;

/// Parcel Wing API error type.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ErrorType {
    AuthenticationError,
    ValidationError,
    InvalidRequestError,
    NotFoundError,
    ConflictError,
    RateLimitError,
    ReputationError,
    SuppressionError,
    ApiError,
    #[serde(other)]
    Unknown,
}

/// API error payload returned by Parcel Wing.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ErrorPayload {
    pub error: ApiError,
}

/// Structured Parcel Wing API error.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ApiError {
    #[serde(default = "default_api_error_type")]
    pub r#type: ErrorType,
    pub code: Option<String>,
    pub message: String,
    pub details: Option<Value>,
    pub request_id: Option<String>,

    #[serde(flatten)]
    pub metadata: HashMap<String, Value>,

    #[serde(skip)]
    pub status: u16,
}

fn default_api_error_type() -> ErrorType {
    ErrorType::ApiError
}

/// Error returned by this SDK.
#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("Parcel Wing API error: {}", .0.message)]
    Api(Box<ApiError>),

    #[error("Parcel Wing SDK configuration error: {0}")]
    Configuration(String),

    #[error("Parcel Wing request failed: {0}")]
    Request(#[from] reqwest::Error),

    #[error("Could not build HTTP client: {0}")]
    HttpClientBuild(reqwest::Error),

    #[error("Could not parse API response: {0}")]
    Decode(#[from] serde_json::Error),

    #[error("Parcel Wing API request failed with status {status}: {body}")]
    Http { status: u16, body: String },
}

impl ApiError {
    pub fn status(&self) -> u16 {
        self.status
    }

    pub fn error_type(&self) -> &ErrorType {
        &self.r#type
    }
}