Quick Reference
A comprehensive reference for all mik-sdk APIs.
Required Imports
Section titled “Required Imports”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 bycargo-componentfrom your WIT filesGuest- The trait your handler implements (generated by theroutes!macro)Response- The response type returned by handlersmik_sdk::prelude::*- All SDK types and macros
Modules
Section titled “Modules”The prelude includes all common modules:
| Module | Purpose |
|---|---|
json | JSON building and 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 |
query | Cursor, PageInfo, Value (with sql feature) |
| Type | Purpose |
|---|---|
Request | HTTP request wrapper |
Method | HTTP method enum |
Id | Built-in single path parameter |
ParseError | JSON/input parsing errors |
ValidationError | Field validation errors |
Derive Macros
Section titled “Derive Macros”| Macro | Purpose |
|---|---|
#[derive(Type)] | JSON body/response with OpenAPI schema |
#[derive(Query)] | Query string parameters with defaults |
#[derive(Path)] | URL path parameters |
Field Attributes
Section titled “Field Attributes”#[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
PascalCasetosnake_caseby 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,}Response Macros
Section titled “Response Macros”| Macro | Status | Purpose |
|---|---|---|
ok!({ ... }) | 200 | JSON response |
created!(location, { ... }) | 201 | Created with Location |
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 Problem Details |
DX Macros
Section titled “DX Macros”| Macro | Purpose |
|---|---|
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 |
SQL Macros
Section titled “SQL Macros”| Macro | Purpose |
|---|---|
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 |
Request Methods
Section titled “Request Methods”| Method | Returns | Description |
|---|---|---|
method() | Method | HTTP method |
path() | &str | Full path with query |
path_without_query() | &str | Path only |
param_or(name, def) | &str | Path parameter |
query_or(name, def) | &str | Query parameter |
query_all(name) | &[String] | All query values |
header_or(name, def) | &str | Header (case-insensitive) |
header_all(name) | Vec<&str> | All header values |
trace_id_or(def) | &str | traceparent header |
bearer_token_or(def) | &str | Bearer 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() | bool | True if non-empty |
content_type_or(def) | &str | Content-Type header |
is_json() | bool | Content-Type is JSON |
is_form() | bool | Content-Type is form |
form_or(name, def) | &str | Form field value |
form_all(name) | &[String] | All form values |
JSON Module
Section titled “JSON Module”Building
Section titled “Building”json::obj() // Empty object {}json::arr() // Empty array []json::str("text") // String valuejson::int(42) // Integer valuejson::float(3.14) // Float valuejson::bool(true) // Boolean valuejson::null() // Null value
// Chainingjson::obj() .set("name", json::str("Alice")) .set("age", json::int(30))
json::arr() .push(json::int(1)) .push(json::int(2))Parsing
Section titled “Parsing”// From requestlet parsed = req.json()?;
// From HTTP responselet 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"]) // boolparsed.path_is_null(&["field"]) // bool
// With defaultsparsed.path_str_or(&["name"], "Anonymous")parsed.path_int_or(&["age"], 0)
// Tree access (triggers full parse)parsed.get("key") // JsonValueparsed.at(0) // JsonValue (array index)parsed.keys() // Vec<String>parsed.len() // Option<usize>Time Module
Section titled “Time Module”time::now() // u64 - Unix secondstime::now_millis() // u64 - Unix millisecondstime::now_iso() // String - ISO 8601
// Convert raw valuestime::to_millis(secs, nanos)time::to_iso(secs, nanos)Random Module
Section titled “Random Module”random::uuid() // String - UUID v4random::hex(n) // String - n bytes as hexrandom::bytes(n) // Vec<u8> - n random bytesrandom::u64() // u64 - random integerLog Module
Section titled “Log Module”// Format-string stylelog::info!("User {} logged in", user_id);log::warn!("Cache miss: {}", key);log::error!("Failed: {}", err);log::debug!("Debug: {:?}", data); // Release: compiled out
// Structured stylelog!(info, "user created", id: user_id, email: &email);log!(warn, "rate limit", remaining: count);log!(error, "fetch failed", url: &url, status: code);Environment Module
Section titled “Environment Module”env::get("KEY") // Option<String>env::get_or("KEY", "default") // Stringenv::require("KEY") // String (panics if missing)Status Constants
Section titled “Status Constants”status::OK // 200status::CREATED // 201status::ACCEPTED // 202status::NO_CONTENT // 204status::MOVED_PERMANENTLY // 301status::FOUND // 302status::BAD_REQUEST // 400status::UNAUTHORIZED // 401status::FORBIDDEN // 403status::NOT_FOUND // 404status::CONFLICT // 409status::UNPROCESSABLE_ENTITY // 422status::TOO_MANY_REQUESTS // 429status::INTERNAL_SERVER_ERROR // 500status::BAD_GATEWAY // 502status::SERVICE_UNAVAILABLE // 503status::GATEWAY_TIMEOUT // 504HTTP Client
Section titled “HTTP Client”// GET requestfetch!(GET "https://api.example.com/data").send()?;
// POST with JSONfetch!(POST "https://api.example.com/users", json: { "name": "Alice"}).send()?;
// With optionsfetch!(GET "https://api.example.com", headers: { "Authorization": format!("Bearer {}", token) }, timeout: 5000).send()?;
// SSRF protectionfetch!(GET &user_url) .deny_private_ips() .send()?;
// Trace propagationlet 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 handlinglet resp = fetch!(GET "https://api.example.com").send()?;resp.is_success() // boolresp.status() // u16resp.body() // Vec<u8>resp.header("name") // Option<&str>SQL Query Builder
Section titled “SQL Query Builder”// SELECTsql_read!(users { select: [id, name, email], filter: { active: true, age: { $gte: 18 } }, order: [-created_at, name], limit: 20,})
// INSERTsql_create!(users { name: "Alice", email: "alice@example.com", returning: [id],})
// UPDATEsql_update!(users { set: { name: "Bob", updated_at: time::now_iso() }, filter: { id: 123 },})
// DELETEsql_delete!(users { filter: { id: 123 },})
// SQLite dialectsql_read!(sqlite, users { ... })Filter Operators
Section titled “Filter Operators”| Operator | Description |
|---|---|
$eq | Equal |
$ne | Not equal |
$gt | Greater than |
$gte | Greater or equal |
$lt | Less than |
$lte | Less or equal |
$in | In list |
$nin | Not in list |
$like | LIKE pattern |
$starts_with | Starts with |
$ends_with | Ends with |
$contains | Contains |
$between | Between range |
$and | Logical AND |
$or | Logical OR |
$not | Logical NOT |
Cursor Pagination
Section titled “Cursor Pagination”use mik_sdk::query::Cursor;
// Encode cursorlet cursor = Cursor::new() .string("created_at", &last.created_at) .int("id", last.id) .encode();
// Use in querysql_read!(posts { order: [-created_at, -id], after: Some(&cursor), limit: 20,})