mik-sdk

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.