Skip to content

Quick Reference

A comprehensive reference for all mik-sdk APIs.

Every handler file needs these imports:

#[allow(warnings)]
mod bindings;
use bindings::exports::mik::core::handler::{self, Guest, Response};
use mik_sdk::prelude::*;
  • bindings - Generated by cargo-component from your WIT files
  • Guest - The trait your handler implements (generated by the routes! macro)
  • Response - The response type returned by handlers
  • mik_sdk::prelude::* - All SDK types and macros

The prelude includes all common modules:

ModulePurpose
jsonJSON building and parsing
timeUTC timestamps and ISO 8601
randomUUIDs, tokens, random bytes
logStructured logging to stderr
envEnvironment variable access
http_clientOutbound HTTP requests
statusHTTP status code constants
queryCursor, PageInfo, Value (with sql feature)
TypePurpose
RequestHTTP request wrapper
MethodHTTP method enum
IdBuilt-in single path parameter
ParseErrorJSON/input parsing errors
ValidationErrorField validation errors
MacroPurpose
#[derive(Type)]JSON body/response with OpenAPI schema
#[derive(Query)]Query string parameters with defaults
#[derive(Path)]URL path parameters
#[derive(Type)]
pub struct Example {
#[field(min = 1, max = 100)]
pub name: String,
#[field(format = "email")]
pub email: String,
#[field(rename = "userName")]
pub user_name: String,
#[field(docs = "Description for OpenAPI")]
pub field: String,
}
#[derive(Query)]
pub struct QueryExample {
#[field(default = 1)]
pub page: u32,
#[field(default = 20, max = 100)]
pub limit: u32,
}

Use #[derive(Type)] on enums to serialize them as JSON strings. Only unit variants (no fields) are supported.

#[derive(Type)]
pub enum Status {
Active, // serializes as "active"
Inactive, // serializes as "inactive"
Pending, // serializes as "pending"
}
#[derive(Type)]
pub enum Priority {
#[field(rename = "HIGH")]
High,
#[field(rename = "MEDIUM")]
Medium,
#[field(rename = "LOW")]
Low,
}

Behavior:

  • Variants are converted from PascalCase to snake_case by default (SuperAdmin"super_admin")
  • Use #[field(rename = "...")] on variants to customize the JSON string
  • Invalid values return a helpful error listing all valid options
  • OpenAPI schema is generated as { "type": "string", "enum": ["active", "inactive", "pending"] }

Usage in structs:

#[derive(Type)]
pub struct Task {
pub id: String,
pub status: Status,
pub priority: Priority,
}
MacroStatusPurpose
ok!({ ... })200JSON response
created!(location, { ... })201Created with Location
accepted!()202Accepted
no_content!()204No Content
redirect!(url)302Redirect
bad_request!(msg)400Bad Request
forbidden!(msg)403Forbidden
not_found!(msg)404Not Found
conflict!(msg)409Conflict
error! { ... }anyRFC 7807 Problem Details
MacroPurpose
guard!(cond, status, msg)Early return if false
ensure!(expr, status, msg)Unwrap or return error
fetch!(METHOD url, ...)Build HTTP request
routes! { ... }Define routes
json!({ ... })Build JSON value
MacroPurpose
sql_read!(table { ... })SELECT query
sql_create!(table { ... })INSERT query
sql_update!(table { ... })UPDATE query
sql_delete!(table { ... })DELETE query
ids!(collection)Extract IDs for batching
MethodReturnsDescription
method()MethodHTTP method
path()&strFull path with query
path_without_query()&strPath only
param_or(name, def)&strPath parameter
query_or(name, def)&strQuery parameter
query_all(name)&[String]All query values
header_or(name, def)&strHeader (case-insensitive)
header_all(name)Vec<&str>All header values
trace_id_or(def)&strtraceparent header
bearer_token_or(def)&strBearer token from Auth
body()Option<&[u8]>Raw body bytes
text()Option<&str>Body as UTF-8
json()Option<JsonValue>Parse as JSON
json_with(parser)Option<T>Parse with custom parser
has_body()boolTrue if non-empty
content_type_or(def)&strContent-Type header
is_json()boolContent-Type is JSON
is_form()boolContent-Type is form
form_or(name, def)&strForm field value
form_all(name)&[String]All form values
json::obj() // Empty object {}
json::arr() // Empty array []
json::str("text") // String value
json::int(42) // Integer value
json::float(3.14) // Float value
json::bool(true) // Boolean value
json::null() // Null value
// Chaining
json::obj()
.set("name", json::str("Alice"))
.set("age", json::int(30))
json::arr()
.push(json::int(1))
.push(json::int(2))
// From request
let parsed = req.json()?;
// From HTTP response
let parsed = resp.json()?;
// From raw bytes (low-level)
let parsed = json::try_parse(bytes)?;
// Path accessors (lazy - fast)
parsed.path_str(&["user", "name"]) // Option<String>
parsed.path_int(&["user", "age"]) // Option<i64>
parsed.path_float(&["metrics", "score"]) // Option<f64>
parsed.path_bool(&["user", "active"]) // Option<bool>
parsed.path_exists(&["field"]) // bool
parsed.path_is_null(&["field"]) // bool
// With defaults
parsed.path_str_or(&["name"], "Anonymous")
parsed.path_int_or(&["age"], 0)
// Tree access (triggers full parse)
parsed.get("key") // JsonValue
parsed.at(0) // JsonValue (array index)
parsed.keys() // Vec<String>
parsed.len() // Option<usize>
time::now() // u64 - Unix seconds
time::now_millis() // u64 - Unix milliseconds
time::now_iso() // String - ISO 8601
// Convert raw values
time::to_millis(secs, nanos)
time::to_iso(secs, nanos)
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
// Format-string style
log::info!("User {} logged in", user_id);
log::warn!("Cache miss: {}", key);
log::error!("Failed: {}", err);
log::debug!("Debug: {:?}", data); // Release: compiled out
// Structured style
log!(info, "user created", id: user_id, email: &email);
log!(warn, "rate limit", remaining: count);
log!(error, "fetch failed", url: &url, status: code);
env::get("KEY") // Option<String>
env::get_or("KEY", "default") // String
env::require("KEY") // String (panics if missing)
status::OK // 200
status::CREATED // 201
status::ACCEPTED // 202
status::NO_CONTENT // 204
status::MOVED_PERMANENTLY // 301
status::FOUND // 302
status::BAD_REQUEST // 400
status::UNAUTHORIZED // 401
status::FORBIDDEN // 403
status::NOT_FOUND // 404
status::CONFLICT // 409
status::UNPROCESSABLE_ENTITY // 422
status::TOO_MANY_REQUESTS // 429
status::INTERNAL_SERVER_ERROR // 500
status::BAD_GATEWAY // 502
status::SERVICE_UNAVAILABLE // 503
status::GATEWAY_TIMEOUT // 504
// GET request
fetch!(GET "https://api.example.com/data").send()?;
// POST with JSON
fetch!(POST "https://api.example.com/users", json: {
"name": "Alice"
}).send()?;
// With options
fetch!(GET "https://api.example.com",
headers: { "Authorization": format!("Bearer {}", token) },
timeout: 5000
).send()?;
// SSRF protection
fetch!(GET &user_url)
.deny_private_ips()
.send()?;
// Trace propagation
let trace_id = req.trace_id_or("");
fetch!(GET "https://api.example.com")
.with_trace_id(if trace_id.is_empty() { None } else { Some(trace_id) })
.send()?;
// Response handling
let resp = fetch!(GET "https://api.example.com").send()?;
resp.is_success() // bool
resp.status() // u16
resp.body() // Vec<u8>
resp.header("name") // Option<&str>
// SELECT
sql_read!(users {
select: [id, name, email],
filter: { active: true, age: { $gte: 18 } },
order: [-created_at, name],
limit: 20,
})
// INSERT
sql_create!(users {
name: "Alice",
email: "alice@example.com",
returning: [id],
})
// UPDATE
sql_update!(users {
set: { name: "Bob", updated_at: time::now_iso() },
filter: { id: 123 },
})
// DELETE
sql_delete!(users {
filter: { id: 123 },
})
// SQLite dialect
sql_read!(sqlite, users { ... })
OperatorDescription
$eqEqual
$neNot equal
$gtGreater than
$gteGreater or equal
$ltLess than
$lteLess or equal
$inIn list
$ninNot in list
$likeLIKE pattern
$starts_withStarts with
$ends_withEnds with
$containsContains
$betweenBetween range
$andLogical AND
$orLogical OR
$notLogical NOT
use mik_sdk::query::Cursor;
// Encode cursor
let cursor = Cursor::new()
.string("created_at", &last.created_at)
.int("id", last.id)
.encode();
// Use in query
sql_read!(posts {
order: [-created_at, -id],
after: Some(&cursor),
limit: 20,
})