paradox-gloo-net

Generate gloo-net async HTTP client modules from Paradox URI specifications.

Define your endpoints in .dox, and paradox-gloo-net generates a Rust module with typed async functions that use gloo_net::http::Request for browser/WASM HTTP calls.

Usage

paradox-gloo-net --uri createUser --uri getUser

All flags:

Flag Default Description

--uri

(required, repeatable)

Name of a spec constant that evaluates to a URI or a product of URIs

--base-path

""

Base path prepended to all generated URLs

--output

.dox/client.rs

Output file path for the generated client module

The --uri flag can be repeated to include endpoints from multiple constants:

paradox-gloo-net --uri publicApi --uri adminApi --base-path "/api/v1"

Example

Given this .dox specification:

import std

type User
  id: Text
  name: Text
  email: Text

type CreateUserRequest
  name: Text
  email: Text

createUser: URI
  http://localhost/users POST (CreateUserRequest. User)

getUser: URI
  http://localhost/users/${Integer id} GET (Unit. User)

listUsers: URI
  http://localhost/users GET (Unit. [User])

Run:

paradox-gloo-net --uri createUser --uri getUser --uri listUsers

This generates .dox/client.rs:

//! Generated by paradox-gloo-net — do not edit

use gloo_net::http::Request;
use crate::{
    CreateUserRequest,
    User
};

const API_BASE: &str = "";

pub async fn create_user(input: &CreateUserRequest) -> Result<User, String> {
    let url = format!("{}/users", API_BASE);
    let response = Request::post(&url)
        .header("Content-Type", "application/json")
        .body(serde_json::to_string(input).map_err(|e| e.to_string())?)
        .map_err(|e| e.to_string())?
        .send()
        .await
        .map_err(|e| e.to_string())?;

    if !response.ok() {
        return Err(format!("HTTP error: {}", response.status()));
    }

    response
        .json::<User>()
        .await
        .map_err(|e| e.to_string())
}

pub async fn get_user(id: i64) -> Result<User, String> {
    let url = format!("{}/users/{}", API_BASE, id);
    let response = Request::get(&url)
        .send()
        .await
        .map_err(|e| e.to_string())?;

    if !response.ok() {
        return Err(format!("HTTP error: {}", response.status()));
    }

    response
        .json::<User>()
        .await
        .map_err(|e| e.to_string())
}

pub async fn list_users() -> Result<Vec<User>, String> {
    let url = format!("{}/users", API_BASE);
    let response = Request::get(&url)
        .send()
        .await
        .map_err(|e| e.to_string())?;

    if !response.ok() {
        return Err(format!("HTTP error: {}", response.status()));
    }

    response
        .json::<Vec<User>>()
        .await
        .map_err(|e| e.to_string())
}

Wiring It Up

mod client;

use client::{create_user, get_user, list_users};
use crate::CreateUserRequest;

async fn example() -> Result<(), String> {
    let new_user = CreateUserRequest {
        name: "Isaac".into(),
        email: "isaac@example.com".into(),
    };
    let user = create_user(&new_user).await?;
    let fetched = get_user(1).await?;
    let all = list_users().await?;
    Ok(())
}

How It Works

paradox-gloo-net operates in three stages:

  1. Evaluate URIs to JSON — For each --uri name, runs paradox generate --json <name> to get the structured URI data

  2. Parse URI configs — Extracts path, meta (HTTP method), and io (input/output types) from each URI

  3. Generate client module — Produces a Rust module with one pub async fn per endpoint

URI Constants vs Products of URIs

The --uri flag accepts either a single URI constant or a product type whose fields are URIs:

| Single URI -- pass as --uri createUser
createUser: URI
  http://localhost/users POST (CreateUserRequest. User)

| Product of URIs -- pass as --uri api
type ApiEndpoints
  createUser: URI
  getUser: URI

api: ApiEndpoints
  ApiEndpoints:
    createUser: http://localhost/users POST (CreateUserRequest. User)
    getUser: http://localhost/users/${Integer id} GET (Unit. User)

Path Parameters

Interpolated type captures in URI paths are converted to function parameters:

.dox Path Parameter Rust Type

/users/${Integer}

integer: i64

i64

/users/${Text id}

id: &str

&str

/users/${Integer id}

id: i64

i64

Type Mapping

Paradox types are mapped to Rust types:

Paradox Type Rust Type

Text

&str (parameters) / String (fields)

Integer

i64

Unit / ()

()

[T]

Vec<T>

Other

Used as-is (e.g., User)

Request Bodies

POST, PUT, and PATCH endpoints with a non-unit input type serialize the input with serde_json and set Content-Type: application/json.

Response Handling

All generated functions return Result<T, String>. Non-2xx responses produce an Err with the HTTP status code. Successful responses are deserialized with response.json::<T>(). Unit output types return Ok(()) without reading the body.

Function Naming

Endpoint names are converted from camelCase to snake_case for idiomatic Rust:

Endpoint Name Function Name

createUser

create_user

getUser

get_user

listUsers

list_users

See Also