mik-sdk

Crates.iomik-sdk
lib.rsmik-sdk
version0.1.2
created_at2025-12-28 07:44:46.446636+00
updated_at2026-01-02 21:41:26.619307+00
descriptionErgonomic macros for WASI HTTP handlers - ok!, error!, json!
homepage
repositoryhttps://github.com/dufeut/mik-sdk
max_upload_size
id2008349
size796,977
(dufeut)

documentation

README

mik-sdk

Crates.io Documentation License: MIT

Ergonomic SDK for building WASI HTTP handlers with pure Rust.

v0.1.x - Published and usable, but evolving. The API may change between minor versions.

Features

  • Type-Safe Routing - routes! macro with path, query, and body extraction
  • Derive Macros - #[derive(Type)], #[derive(Query)], #[derive(Path)]
  • Response Helpers - ok!, error! with RFC 7807 support
  • SQL Builder - sql_read!, sql_create! with cursor pagination
  • Minimal - ~200KB composed component size

Quick Start

use mik_sdk::prelude::*;

// Define typed inputs with derive macros
#[derive(Type)]
pub struct HelloResponse {
    pub greeting: String,
    pub name: String,
}

#[derive(Path)]
pub struct HelloPath {
    pub name: String,
}

#[derive(Query)]
pub struct SearchQuery {
    pub q: Option<String>,
    #[field(default = 1)]
    pub page: u32,
    #[field(default = 10, max = 100)]
    pub limit: u32,
}

// Define routes with typed inputs
routes! {
    GET "/" => home,
    GET "/hello/{name}" => hello(path: HelloPath) -> HelloResponse,
    GET "/search" => search(query: SearchQuery),
}

fn home(_req: &Request) -> Response {
    ok!({ "message": "Welcome!" })
}

fn hello(path: HelloPath, _req: &Request) -> Response {
    ok!({
        "greeting": format!("Hello, {}!", path.name),
        "name": path.name
    })
}

fn search(query: SearchQuery, _req: &Request) -> Response {
    ok!({
        "query": query.q,
        "page": query.page,
        "limit": query.limit
    })
}

Core Macros

Response Macros

ok!({ "data": value })                    // 200 OK with JSON
error! { status: 404, title: "Not Found" } // RFC 7807 error
created!("/users/123", { "id": "123" })   // 201 Created with Location
no_content!()                              // 204 No Content

Routing

routes! {
    GET "/" => home,
    GET "/users/{id}" => get_user(path: Id) -> User,
    POST "/users" => create_user(body: CreateInput) -> User,
    GET "/search" => search(query: SearchQuery),
}

DX Macros

guard!(!name.is_empty(), 400, "Name required");      // Early return validation
let user = ensure!(find_user(id), 404, "Not found"); // Unwrap or return error

For JSON body parsing, use typed inputs with #[derive(Type)] - the body is parsed automatically in the route handler.

SQL Builder

let (sql, params) = sql_read!(users {
    select: [id, name, email],
    filter: { active: true },
    order: [-created_at, id],
    after: cursor,
    limit: 20,
});

HTTP Client

// Simple request
let resp = fetch!(GET "https://api.example.com/users").send()?;

// POST with JSON body
let resp = fetch!(POST "https://api.example.com/users", json: {
    "name": "Alice"
}).send()?;

// SSRF protection for user-provided URLs
let resp = fetch!(GET &user_url)
    .deny_private_ips()  // Blocks localhost, 10.x, 192.168.x, etc.
    .send()?;

Request Helpers

req.param("id")          // Path parameter: Option<&str>
req.query("page")        // Query parameter: Option<&str>
req.header("auth")       // Header (case-insensitive): Option<&str>
req.body()               // Raw body: Option<&[u8]>
req.text()               // Body as UTF-8: Option<&str>
req.is_json()            // Content-Type is JSON: bool
req.is_html()            // Content-Type is HTML: bool
req.is_form()            // Content-Type is form: bool
req.accepts("json")      // Accept header check: bool

Type Inference

Variables work directly in ok! and json! macros via the ToJson trait:

ok!({
    "name": name,       // String → JSON string
    "age": age,         // i32 → JSON integer
    "score": score,     // Option<f64> → JSON number or null
    "tags": tags        // Vec<&str> → JSON array
})

Type hints available for explicit control: str(), int(), float(), bool()

API Reference

Modules

Module Purpose
json JSON building and lazy parsing
time UTC timestamps and ISO 8601
random UUIDs, tokens, random bytes
log Structured logging to stderr
env Environment variable access
http_client Outbound HTTP requests
status HTTP status code constants

Response Macros

Macro Status Description
ok!({ ... }) 200 JSON response
created!(loc, { ... }) 201 With Location header
accepted!() 202 Accepted
no_content!() 204 No Content
redirect!(url) 302 Redirect
bad_request!(msg) 400 Bad Request
forbidden!(msg) 403 Forbidden
not_found!(msg) 404 Not Found
conflict!(msg) 409 Conflict
error! { ... } any RFC 7807

DX Macros

Macro Purpose
guard!(cond, status, msg) Early return if false
ensure!(expr, status, msg) Unwrap or return error
fetch!(METHOD url, ...) HTTP client request
ids!(collection) Extract IDs for batching

SQL Macros

Macro Purpose
sql_read!(table { ... }) SELECT
sql_create!(table { ... }) INSERT
sql_update!(table { ... }) UPDATE
sql_delete!(table { ... }) DELETE

time Module

Function Returns
time::now() u64 - Unix seconds
time::now_millis() u64 - Unix milliseconds
time::now_iso() String - ISO 8601

random Module

Function Returns
random::uuid() String - UUID v4
random::hex(n) String - n bytes as hex
random::bytes(n) Vec<u8> - n random bytes
random::u64() u64 - Random integer

Request Methods

Method Returns
param(name) Option<&str>
query(name) Option<&str>
query_all(name) &[String]
header(name) Option<&str>
header_all(name) Vec<&str>
trace_id() Option<&str>
body() Option<&[u8]>
text() Option<&str>
json() Option<JsonValue>
json_with(parser) Option<T>
form(name) Option<&str>
form_all(name) &[String]
is_json() bool
is_form() bool
is_html() bool
accepts(mime) bool
has_body() bool
content_type() Option<&str>

Logging

// Format-string style
log::info!("User {} logged in", id);
log::warn!("Cache miss: {}", key);
log::error!("Failed: {}", err);
log::debug!("Debug: {:?}", data);  // Compiled out in release

// Structured style (JSON output)
log!(info, "user created", id: user_id, email: &email);

Feature Flags

[dependencies]
mik-sdk = "0.1"  # Includes sql + http-client by default

# Minimal build
mik-sdk = { version = "0.1", default-features = false }
Feature Default Description
sql Yes SQL query builder macros
http-client Yes HTTP client with .send()

Configuration

Environment variables for runtime limits:

Variable Default Description
MIK_MAX_JSON_SIZE 1 MB Maximum JSON input size for parsing
MIK_MAX_BODY_SIZE 10 MB Maximum request body size (bridge)

Requirements

  • Rust 1.89+ (Edition 2024)
  • Target: wasm32-wasip2
  • Build tool: cargo-component

License

Licensed under MIT license. See LICENSE-MIT.

Commit count: 0

cargo fmt