use common::ron_api; use gloo::net::http::{Request, RequestBuilder}; use serde::{de::DeserializeOwned, Serialize}; use thiserror::Error; use crate::toast::{self, Level}; #[derive(Error, Debug)] pub enum Error { #[error("Gloo error: {0}")] Gloo(#[from] gloo::net::Error), #[error("RON Spanned error: {0}")] Ron(#[from] ron::error::SpannedError), #[error("HTTP error: {0}")] Http(String), #[error("Unknown error: {0}")] Other(String), } type Result = std::result::Result; const CONTENT_TYPE: &str = "Content-Type"; const CONTENT_TYPE_RON: &str = "application/ron"; async fn req_with_body( api_name: &str, body: U, method_fn: fn(&str) -> RequestBuilder, ) -> Result where T: DeserializeOwned, U: Serialize, { let url = format!("/ron-api/{}", api_name); let request_builder = method_fn(&url).header(CONTENT_TYPE, CONTENT_TYPE_RON); send_req(request_builder.body(ron_api::to_string(body))?).await } async fn req_with_params<'a, T, U, V>( api_name: &str, params: U, method_fn: fn(&str) -> RequestBuilder, ) -> Result where T: DeserializeOwned, U: IntoIterator, V: AsRef, { let url = format!("/ron-api/{}", api_name); let request_builder = method_fn(&url) .header(CONTENT_TYPE, CONTENT_TYPE_RON) .query(params); send_req(request_builder.build()?).await } async fn send_req(request: Request) -> Result where T: DeserializeOwned, { match request.send().await { Err(error) => { toast::show(Level::Info, &format!("Internal server error: {}", error)); Err(Error::Gloo(error)) } Ok(response) => { if !response.ok() { toast::show( Level::Info, &format!("HTTP error: {}", response.status_text()), ); Err(Error::Http(response.status_text())) } else { // Ok(()) Ok(ron::de::from_bytes::(&response.binary().await?)?) } } } } pub async fn put(api_name: &str, body: U) -> Result where T: DeserializeOwned, U: Serialize, { req_with_body(api_name, body, Request::put).await } pub async fn post(api_name: &str, body: U) -> Result where T: DeserializeOwned, U: Serialize, { req_with_body(api_name, body, Request::post).await } pub async fn delete(api_name: &str, body: U) -> Result where T: DeserializeOwned, U: Serialize, { req_with_body(api_name, body, Request::delete).await } pub async fn get<'a, T, U, V>(api_name: &str, params: U) -> Result where T: DeserializeOwned, U: IntoIterator, V: AsRef, { req_with_params(api_name, params, Request::get).await } // pub async fn api_request_get(api_name: &str, params: QueryParams) -> Result // where // T: DeserializeOwned, // { // match Request::get(&format!("/ron-api/recipe/{}?{}", api_name, params)) // .header("Content-Type", "application/ron") // .send() // .await // { // Err(error) => { // toast::show(Level::Info, &format!("Internal server error: {}", error)); // Err(error.to_string()) // } // Ok(response) => Ok(ron::de::from_bytes::(&response.binary().await.unwrap()).unwrap()), // } // }