avina 2.2.0

Rust client library for the LRZ-specific features of the Openstack-based LRZ Compute Cloud.
Documentation
use std::fmt::Debug;

use anyhow::Context;
use avina_wire::error::ErrorResponse;
use reqwest::{Client, Method, Response, StatusCode};
use serde::{de::DeserializeOwned, ser::Serialize};

use crate::error::ApiError;

#[derive(serde::Serialize, Debug)]
pub(crate) struct SerializableFoo {}
macro_rules! SerializableNone {
    () => {
        None::<crate::common::SerializableFoo>
    };
}
pub(crate) use SerializableNone;

pub(crate) async fn request_bare<T>(
    client: &Client,
    method: Method,
    url: &str,
    data: Option<T>,
    expected_status: StatusCode,
) -> Result<Response, ApiError>
where
    T: Serialize + Debug,
{
    let mut request = client.request(method, url);
    if let Some(data) = data {
        request = request.body(serde_json::to_string(&data).context(
            format!("Could not serialize json request body from {data:?}"),
        )?);
    }
    let response = match request.send().await.context("") {
        Ok(response) => response,
        Err(err) => {
            let detail =
                format!("Could not complete request: {}", err.root_cause());
            return Err(ApiError::ResponseError(detail));
        }
    };
    let status = response.status();
    if status != expected_status {
        let text = response.text().await.context(format!(
            "Could not retrieve response text on unexpected status code {status}.",
        ))?;
        let err_resp: ErrorResponse = serde_json::from_str(text.as_str())
            .context(format!(
                "Unexpected status code {status} without error message.",
            ))?;
        return Err(ApiError::ResponseError(err_resp.detail));
    }
    Ok(response)
}

pub(crate) async fn request<T, U>(
    client: &Client,
    method: Method,
    url: &str,
    data: Option<T>,
    expected_status: StatusCode,
) -> Result<U, ApiError>
where
    T: Serialize + Debug,
    U: DeserializeOwned,
{
    let response =
        request_bare(client, method, url, data, expected_status).await?;
    let text = response
        .text()
        .await
        .context("Could not retrieve response text.")?;
    let u: U = serde_json::from_str(text.as_str())
        .context(format!("Could not parse response text: {text}"))?;
    Ok(u)
}