openfga 1.0.2

Rust SDK for OpenFGA — the open-source authorization system
Documentation
use std::error;
use std::fmt;

#[derive(Debug, Clone)]
pub struct ResponseContent<T> {
    pub status: reqwest::StatusCode,
    pub content: String,
    pub entity: Option<T>,
}

#[derive(Debug)]
pub enum Error<T> {
    Reqwest(reqwest::Error),
    Serde(serde_json::Error),
    Io(std::io::Error),
    ResponseError(ResponseContent<T>),
}

impl<T: fmt::Debug> fmt::Display for Error<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let (module, e) = match self {
            Error::Reqwest(e) => ("reqwest", e.to_string()),
            Error::Serde(e) => ("serde", e.to_string()),
            Error::Io(e) => ("IO", e.to_string()),
            Error::ResponseError(e) => {
                let detail = e
                    .entity
                    .as_ref()
                    .map(|en| format!("{en:?}"))
                    .unwrap_or_default();
                ("response", format!("status code {}{}", e.status, detail))
            }
        };
        write!(f, "error in {}: {}", module, e)
    }
}

impl<T: fmt::Debug> error::Error for Error<T> {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        Some(match self {
            Error::Reqwest(e) => e,
            Error::Serde(e) => e,
            Error::Io(e) => e,
            Error::ResponseError(_) => return None,
        })
    }
}

impl<T> From<reqwest::Error> for Error<T> {
    fn from(e: reqwest::Error) -> Self {
        Error::Reqwest(e)
    }
}

impl<T> From<serde_json::Error> for Error<T> {
    fn from(e: serde_json::Error) -> Self {
        Error::Serde(e)
    }
}

impl<T> From<std::io::Error> for Error<T> {
    fn from(e: std::io::Error) -> Self {
        Error::Io(e)
    }
}

/// Percent-encodes a string for use in a URL path segment (RFC 3986).
///
/// Unlike `form_urlencoded`, this encodes spaces as `%20` (not `+`) and
/// is safe for use in path segments where `+` has no special meaning.
pub fn urlencode<T: AsRef<str>>(s: T) -> String {
    use percent_encoding::{AsciiSet, CONTROLS, utf8_percent_encode};
    /// Characters that must be percent-encoded in a URL path segment.
    const PATH_SEGMENT: &AsciiSet = &CONTROLS
        .add(b' ')
        .add(b'"')
        .add(b'<')
        .add(b'>')
        .add(b'`')
        .add(b'#')
        .add(b'?')
        .add(b'{')
        .add(b'}')
        .add(b'/')
        .add(b'%')
        .add(b'@')
        .add(b':');
    utf8_percent_encode(s.as_ref(), PATH_SEGMENT).to_string()
}

pub async fn parse_response<T, E>(resp: reqwest::Response) -> Result<T, Error<E>>
where
    T: serde::de::DeserializeOwned,
    E: serde::de::DeserializeOwned,
{
    let status = resp.status();
    let content = resp.text().await?;
    if status.is_success() {
        serde_json::from_str(&content).map_err(Error::from)
    } else {
        let entity = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

pub async fn parse_empty_response<E>(resp: reqwest::Response) -> Result<(), Error<E>>
where
    E: serde::de::DeserializeOwned,
{
    let status = resp.status();
    if status.is_success() {
        Ok(())
    } else {
        let content = resp.text().await?;
        let entity = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

pub mod assertions_api;
pub mod auth_zen_service_api;
pub mod authorization_models_api;
pub mod relationship_queries_api;
pub mod relationship_tuples_api;
pub mod stores_api;

pub mod configuration;