graphile_worker_admin_ui_client 0.1.3

Leptos WASM client for the embedded graphile_worker admin UI
Documentation
use gloo_net::http::{Request, RequestBuilder};
use serde::de::DeserializeOwned;
use serde::Serialize;
use web_sys::RequestCredentials;

use super::super::types::{AdminClientConfig, AuthMode, ErrorResponse};

pub(super) async fn api_get<T>(
    path: &str,
    config: &AdminClientConfig,
    token: &str,
) -> Result<T, String>
where
    T: DeserializeOwned,
{
    let response = with_api_headers(Request::get(path), config, token, false)
        .send()
        .await
        .map_err(|error| error.to_string())?;
    parse_response(response).await
}

pub(super) async fn api_post<B, T>(
    path: &str,
    body: &B,
    config: &AdminClientConfig,
    token: &str,
) -> Result<T, String>
where
    B: Serialize + ?Sized,
    T: DeserializeOwned,
{
    let request = with_api_headers(Request::post(path), config, token, true)
        .json(body)
        .map_err(|error| error.to_string())?;
    let response = request.send().await.map_err(|error| error.to_string())?;
    parse_response(response).await
}

fn with_api_headers(
    builder: RequestBuilder,
    config: &AdminClientConfig,
    token: &str,
    writes: bool,
) -> RequestBuilder {
    let mut builder = builder
        .credentials(RequestCredentials::SameOrigin)
        .header("Accept", "application/json");

    if writes {
        builder = builder.header(&config.csrf_header, &config.csrf);
    }
    if token.is_empty() {
        return builder;
    }

    match config.auth_mode {
        AuthMode::Bearer => {
            builder = builder.header("Authorization", &format!("Bearer {token}"));
        }
        AuthMode::Header if !config.auth_header.is_empty() => {
            builder = builder.header(&config.auth_header, token);
        }
        _ => {}
    }
    builder
}

async fn parse_response<T>(response: gloo_net::http::Response) -> Result<T, String>
where
    T: DeserializeOwned,
{
    let status = response.status();
    let text = response.text().await.map_err(|error| error.to_string())?;
    if !(200..300).contains(&status) {
        return Err(serde_json::from_str::<ErrorResponse>(&text)
            .map(|error| error.error)
            .unwrap_or_else(|_| format!("{status}: {text}")));
    }
    serde_json::from_str(&text).map_err(|error| error.to_string())
}