Quick Start
Build a complete HTTP handler in minutes. This guide covers the essential patterns you’ll use in every mik-sdk project.
Your First Handler
Section titled “Your First Handler”-
Create the project structure
Terminal window cargo new --lib hello-handlercd hello-handler -
Configure Cargo.toml
[package]name = "hello-handler"version = "0.1.0"edition = "2024"[lib]crate-type = ["cdylib"][dependencies]mik-sdk = "0.1"[package.metadata.component]package = "hello:handler"[package.metadata.component.target.dependencies]"mik:core" = { path = "wit/deps/core" } -
Add WIT files
Download the WIT interface:
Terminal window mkdir -p wit/deps/corecurl -L https://github.com/dufeutech/mik-sdk/releases/latest/download/core.wit \-o wit/deps/core/core.witCreate
wit/world.wit:package hello:handler;world handler {include mik:core/handler-world;} -
Write your handler
src/lib.rs #[allow(warnings)]mod bindings;use bindings::exports::mik::core::handler::{self, Guest, Response};use mik_sdk::prelude::*;// Define input types#[derive(Path)]pub struct HelloPath {pub name: String,}#[derive(Type)]pub struct HelloResponse {pub greeting: String,}// Define routesroutes! {GET "/" => home,GET "/hello/{name}" => hello(path: HelloPath) -> HelloResponse,}// Implement handlersfn home(_req: &Request) -> Response {ok!({"message": "Welcome to mik-sdk!","endpoints": ["/", "/hello/{name}"]})}fn hello(path: HelloPath, _req: &Request) -> Response {ok!({"greeting": format!("Hello, {}!", path.name)})} -
Build the component
Terminal window cargo component build --release -
Get the bridge and compose
Terminal window # Download the bridge (if you don't have it)curl -LO https://github.com/dufeutech/mik-sdk/releases/latest/download/mik-bridge.wasm# Compose handler with bridgewac plug mik-bridge.wasm \--plug target/wasm32-wasip2/release/hello_handler.wasm \-o service.wasm -
Run locally
Terminal window wasmtime serve -S cli=y service.wasm -
Test your handler
Terminal window curl http://localhost:8080/curl http://localhost:8080/hello/World
Understanding the Code
Section titled “Understanding the Code”Bindings Module
Section titled “Bindings Module”#[allow(warnings)]mod bindings;The bindings module is generated by cargo-component from your WIT files. It provides the typed interface for your handler.
Derive Macros
Section titled “Derive Macros”#[derive(Path)]pub struct HelloPath { pub name: String, // Matches {name} in the route}
#[derive(Type)]pub struct HelloResponse { pub greeting: String,}| Macro | Purpose |
|---|---|
#[derive(Type)] | JSON request/response body |
#[derive(Path)] | URL path parameters |
#[derive(Query)] | Query string parameters |
Routes Definition
Section titled “Routes Definition”routes! { GET "/" => home, GET "/hello/{name}" => hello(path: HelloPath) -> HelloResponse,}The routes! macro:
- Maps HTTP methods and paths to handler functions
- Extracts typed inputs (path, query, body)
- Generates the
Guestimplementation - Generates OpenAPI schema (via
cargo test __mik_write_schema)
Handler Functions
Section titled “Handler Functions”fn hello(path: HelloPath, _req: &Request) -> Response { ok!({ "greeting": format!("Hello, {}!", path.name) })}Handlers receive:
- Typed inputs (path, query, body) - already parsed and validated
- The raw
&Requestfor accessing headers, raw body, etc.
Adding More Features
Section titled “Adding More Features”Query Parameters
Section titled “Query Parameters”#[derive(Query)]pub struct SearchQuery { pub q: Option<String>, #[field(default = 1)] pub page: u32, #[field(default = 20, max = 100)] pub limit: u32,}
routes! { GET "/search" => search(query: SearchQuery),}
fn search(query: SearchQuery, _req: &Request) -> Response { ok!({ "query": query.q, "page": query.page, "limit": query.limit })}Request Body
Section titled “Request Body”#[derive(Type)]pub struct CreateUserInput { #[field(min = 1, max = 100)] pub name: String, pub email: String,}
routes! { POST "/users" => create_user(body: CreateUserInput),}
fn create_user(body: CreateUserInput, _req: &Request) -> Response { // body is already parsed and validated let id = random::uuid(); created!(format!("/users/{}", id), { "id": id, "name": body.name, "email": body.email })}Error Responses
Section titled “Error Responses”fn get_user(path: Id, _req: &Request) -> Response { let user_id = path.as_str();
// Guard macro for validation guard!(!user_id.is_empty(), 400, "User ID required");
// Ensure macro for Option/Result let user = ensure!(find_user(user_id), 404, "User not found");
ok!({ "user": user })}