zammad-api 0.4.0

Async, idiomatic Rust client for the Zammad Service Platform
Documentation
use serde_json::Value;
use thiserror::Error;

/// Convenience alias for `Result<T, zammad_api::Error>`.
pub type Result<T, E = Error> = std::result::Result<T, E>;

/// Every error this crate can produce.
#[derive(Debug, Error)]
pub enum Error {
    /// The base URL passed to the builder could not be parsed.
    #[error("invalid base URL: {0}")]
    InvalidUrl(#[from] url::ParseError),

    /// Transport-level failure (DNS, TLS, timeout, broken pipe, ...).
    #[error("HTTP error: {0}")]
    Http(#[from] reqwest::Error),

    /// The server responded with a non-success status code.
    #[error("Zammad API error ({status}): {message}")]
    Api {
        /// HTTP status code returned by Zammad.
        status: u16,
        /// Decoded `error` / `error_human` field, or the raw response body.
        message: String,
    },

    /// The requested resource does not exist (HTTP 404).
    #[error("resource not found")]
    NotFound,

    /// A write was issued but the server did not persist the new value.
    ///
    /// Zammad silently returns `200 OK` with the unchanged entity when you
    /// PUT to a custom field that is not declared on the object - this
    /// variant turns that into a loud, actionable failure. The `actual`
    /// value is whatever the server echoed back for `field` (often `null`
    /// or the previous value).
    #[error(
        "write verification failed: field `{field}` was not persisted (got {actual:?}); \
         ensure the custom attribute exists and any pending migrations have been executed"
    )]
    WriteVerificationFailed {
        /// Name of the field that failed to persist.
        field: String,
        /// Value the server returned after the write.
        actual: Option<Value>,
    },

    /// The server returned an unexpected payload.
    #[error("decode error: {0}")]
    Decode(#[from] serde_json::Error),

    /// The configuration passed to [`crate::ClientBuilder`] is invalid.
    #[error("invalid configuration: {0}")]
    Config(String),
}