AkurAI Build
Menu

Public repository / 3aae9f4e85241bcb775c31f5c03094becd3da56a

AkurAI-Framework / crates/ui/src/http.rs

Latest change 3aae9f4e85241bcb775c31f5c03094becd3da56a - Pure-Rust UI layer: akurai-ui, akurai-crypto, Tailwind-grade akurai-css by Ólafur Búi Ólafsson

//! `fetch` with JSON helpers. Same-origin, cookies included.

use crate::callbacks;
use crate::host;
use akurai_json::Value;

/// A completed HTTP exchange. `status` is 0 on a network failure.
#[derive(Clone, Debug, PartialEq)]
pub struct Response {
    pub status: u16,
    pub body: String,
}

impl Response {
    pub fn ok(&self) -> bool {
        (200..300).contains(&self.status)
    }
    /// Parse the body as JSON (`Value::Null` when empty or invalid).
    pub fn json(&self) -> Value {
        akurai_json::parse(&self.body).unwrap_or(Value::Null)
    }
    /// The `error` field of a JSON error body, or a generic message.
    pub fn error_message(&self) -> String {
        match self.json().get("error").and_then(Value::as_str) {
            Some(msg) => msg.to_string(),
            None if self.status == 0 => "Network error — check your connection".to_string(),
            None => format!("Request failed ({})", self.status),
        }
    }
}

/// Send a request; `done` runs when it completes.
pub fn fetch(method: &str, url: &str, body: Option<&str>, done: impl FnOnce(Response) + 'static) {
    let mut done = Some(done);
    let mut run = crate::dom::in_scope(crate::reactive::current_scope(), move |r: Response| {
        if let Some(done) = done.take() {
            done(r)
        }
    });
    let id = callbacks::once(move |status, body| run(Response { status, body }));
    host::fetch(method, url, body, id);
}

pub fn get(url: &str, done: impl FnOnce(Response) + 'static) {
    fetch("GET", url, None, done)
}

/// Send `body` as JSON.
pub fn send_json(method: &str, url: &str, body: &Value, done: impl FnOnce(Response) + 'static) {
    fetch(method, url, Some(&body.to_json()), done)
}