openfga 1.0.1

Rust SDK for OpenFGA — the open-source authorization system
Documentation
/*
 * OpenFGA
 *
 * A high performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar.
 *
 * The version of the OpenAPI document: 1.x
 * Contact: community@openfga.dev
 * Generated by: https://openapi-generator.tech
 */

use super::{Error, ResponseContent, configuration, parse_response};
use crate::models;
use serde::{Deserialize, Serialize};

/// struct for typed errors of method [`batch_check`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum BatchCheckError {
    Status400(models::ValidationErrorMessageResponse),
    Status401(models::UnauthenticatedResponse),
    Status403(models::ForbiddenResponse),
    Status404(models::PathUnknownErrorMessageResponse),
    Status409(models::AbortedMessageResponse),
    Status422(models::UnprocessableContentMessageResponse),
    Status500(models::InternalErrorMessageResponse),
}

/// struct for typed errors of method [`check`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum CheckError {
    Status400(models::ValidationErrorMessageResponse),
    Status401(models::UnauthenticatedResponse),
    Status403(models::ForbiddenResponse),
    Status404(models::PathUnknownErrorMessageResponse),
    Status409(models::AbortedMessageResponse),
    Status422(models::UnprocessableContentMessageResponse),
    Status500(models::InternalErrorMessageResponse),
}

/// struct for typed errors of method [`expand`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ExpandError {
    Status400(models::ValidationErrorMessageResponse),
    Status401(models::UnauthenticatedResponse),
    Status403(models::ForbiddenResponse),
    Status404(models::PathUnknownErrorMessageResponse),
    Status409(models::AbortedMessageResponse),
    Status422(models::UnprocessableContentMessageResponse),
    Status500(models::InternalErrorMessageResponse),
}

/// struct for typed errors of method [`list_objects`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ListObjectsError {
    Status400(models::ValidationErrorMessageResponse),
    Status401(models::UnauthenticatedResponse),
    Status403(models::ForbiddenResponse),
    Status404(models::PathUnknownErrorMessageResponse),
    Status409(models::AbortedMessageResponse),
    Status422(models::UnprocessableContentMessageResponse),
    Status500(models::InternalErrorMessageResponse),
}

/// struct for typed errors of method [`list_users`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ListUsersError {
    Status400(models::ValidationErrorMessageResponse),
    Status401(models::UnauthenticatedResponse),
    Status403(models::ForbiddenResponse),
    Status404(models::PathUnknownErrorMessageResponse),
    Status409(models::AbortedMessageResponse),
    Status422(models::UnprocessableContentMessageResponse),
    Status500(models::InternalErrorMessageResponse),
}

/// struct for typed errors of method [`streamed_list_objects`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum StreamedListObjectsError {
    Status400(models::ValidationErrorMessageResponse),
    Status401(models::UnauthenticatedResponse),
    Status403(models::ForbiddenResponse),
    Status404(models::PathUnknownErrorMessageResponse),
    Status409(models::AbortedMessageResponse),
    Status422(models::UnprocessableContentMessageResponse),
    Status500(models::InternalErrorMessageResponse),
}

/// The `BatchCheck` API functions nearly identically to `Check`, but instead of checking a single user-object relationship BatchCheck accepts a list of relationships to check and returns a map containing `BatchCheckItem` response for each check it received.
pub async fn batch_check(
    configuration: &configuration::Configuration,
    store_id: &str,
    body: models::BatchCheckRequest,
) -> Result<models::BatchCheckResponse, Error<BatchCheckError>> {
    let uri_str = format!(
        "{}/stores/{store_id}/batch-check",
        configuration.base_path,
        store_id = crate::apis::urlencode(store_id)
    );
    let req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);
    let req_builder = configuration.apply_to_request(req_builder);
    let req_builder = req_builder.json(&body);
    let resp = req_builder.send().await?;
    parse_response(resp).await
}

/// The Check API returns whether a given user has a relationship with a given object in a given store.
pub async fn check(
    configuration: &configuration::Configuration,
    store_id: &str,
    body: models::CheckRequest,
) -> Result<models::CheckResponse, Error<CheckError>> {
    let uri_str = format!(
        "{}/stores/{store_id}/check",
        configuration.base_path,
        store_id = crate::apis::urlencode(store_id)
    );
    let req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);
    let req_builder = configuration.apply_to_request(req_builder);
    let req_builder = req_builder.json(&body);
    let resp = req_builder.send().await?;
    parse_response(resp).await
}

/// The Expand API will return all users and usersets that have certain relationship with an object in a certain store.
pub async fn expand(
    configuration: &configuration::Configuration,
    store_id: &str,
    body: models::ExpandRequest,
) -> Result<models::ExpandResponse, Error<ExpandError>> {
    let uri_str = format!(
        "{}/stores/{store_id}/expand",
        configuration.base_path,
        store_id = crate::apis::urlencode(store_id)
    );
    let req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);
    let req_builder = configuration.apply_to_request(req_builder);
    let req_builder = req_builder.json(&body);
    let resp = req_builder.send().await?;
    parse_response(resp).await
}

/// The ListObjects API returns a list of all the objects of the given type that the user has a relation with.
pub async fn list_objects(
    configuration: &configuration::Configuration,
    store_id: &str,
    body: models::ListObjectsRequest,
) -> Result<models::ListObjectsResponse, Error<ListObjectsError>> {
    let uri_str = format!(
        "{}/stores/{store_id}/list-objects",
        configuration.base_path,
        store_id = crate::apis::urlencode(store_id)
    );
    let req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);
    let req_builder = configuration.apply_to_request(req_builder);
    let req_builder = req_builder.json(&body);
    let resp = req_builder.send().await?;
    parse_response(resp).await
}

/// The ListUsers API returns a list of all the users of a specific type that have a relation to a given object.
pub async fn list_users(
    configuration: &configuration::Configuration,
    store_id: &str,
    body: models::ListUsersRequest,
) -> Result<models::ListUsersResponse, Error<ListUsersError>> {
    let uri_str = format!(
        "{}/stores/{store_id}/list-users",
        configuration.base_path,
        store_id = crate::apis::urlencode(store_id)
    );
    let req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);
    let req_builder = configuration.apply_to_request(req_builder);
    let req_builder = req_builder.json(&body);
    let resp = req_builder.send().await?;
    parse_response(resp).await
}

/// The Streamed ListObjects API streams results as they are collected rather than waiting to collect all objects before responding.
/// The server sends newline-delimited JSON (NDJSON); each line is a `StreamResultOfStreamedListObjectsResponse`.
/// Returns successfully-streamed objects, unwrapping the `result` field of each line.
///
/// Lines are processed incrementally as they arrive from the network rather than
/// buffering the full response body first.
pub async fn streamed_list_objects(
    configuration: &configuration::Configuration,
    store_id: &str,
    body: models::ListObjectsRequest,
) -> Result<Vec<models::StreamedListObjectsResponse>, Error<StreamedListObjectsError>> {
    use futures_util::TryStreamExt;
    use tokio::io::AsyncBufReadExt;
    use tokio_util::io::StreamReader;

    let uri_str = format!(
        "{}/stores/{store_id}/streamed-list-objects",
        configuration.base_path,
        store_id = crate::apis::urlencode(store_id)
    );
    let req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);
    let req_builder = configuration.apply_to_request(req_builder);
    let req_builder = req_builder.json(&body);
    let resp = req_builder.send().await?;

    let status = resp.status();
    if !status.is_success() {
        let content = resp.text().await?;
        let entity: Option<StreamedListObjectsError> = serde_json::from_str(&content).ok();
        return Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }));
    }

    // Server streams NDJSON: one JSON object per line.
    // Each line is a StreamResultOfStreamedListObjectsResponse with either a
    // `result` (success) or an `error` (server-side stream failure) field set.
    // Lines are read incrementally from the byte stream without buffering the
    // entire response body.
    let byte_stream = resp.bytes_stream().map_err(std::io::Error::other);
    let reader = StreamReader::new(byte_stream);
    let mut lines = reader.lines();

    let mut results = Vec::new();
    while let Some(line) = lines.next_line().await? {
        let trimmed = line.trim().to_owned();
        if trimmed.is_empty() {
            continue;
        }
        let item: models::StreamResultOfStreamedListObjectsResponse =
            serde_json::from_str(&trimmed).map_err(Error::from)?;
        if let Some(err) = item.error {
            // Propagate server-side stream errors — do not silently drop them.
            return Err(Error::ResponseError(ResponseContent {
                status: reqwest::StatusCode::INTERNAL_SERVER_ERROR,
                content: format!(
                    "stream error {}: {}",
                    err.code
                        .map(|c| c.to_string())
                        .unwrap_or_else(|| "unknown".to_string()),
                    err.message.unwrap_or_default()
                ),
                entity: None,
            }));
        }
        if let Some(result) = item.result {
            results.push(result);
        }
    }
    Ok(results)
}