Route Parameters and Middleware
Prefixing a route segment with : captures its value in req.params. The query
string is available in req.query; the ?? operator applies a default when
the key is absent:
:id, req.params, req.query and ?? for optional values.
// Feature: HTTP server — path params (`:id`) and query string
// Syntax: `:name` in the route; read via `req.params.name` and `req.query.k`.
// When to use: REST routes with IDs, slugs, optional filters.
use std::http
@get("/users/:id")
fn get_user(req) {
// `req.params` carries the matched segments.
let id = req.params.id
return #{
id,
name: "User {id}",
}
}
@get("/search")
fn search(req) {
// `req.query` is a map; `??` applies a default if absent.
let q = req.query.q ?? "(empty)"
let limit = req.query.limit ?? "10"
return #{
q,
limit,
}
}
@get("/posts/:author/:slug")
fn get_post(req) {
return #{
author: req.params.author,
slug: req.params.slug,
}
}
http.serve(3002)
// expected when running:
// curl http://localhost:3002/users/42 -> {"id":"42","name":"User 42"}
// curl 'http://localhost:3002/search?q=zolo&limit=5' -> {"q":"zolo","limit":"5"}
// curl http://localhost:3002/posts/devzolo/hello -> {"author":"devzolo","slug":"hello"}
Requires the Zolo CLI/host — open in the playground or run locally.
Middleware is a function fn mw(req, next) that can inspect the request,
call next(req) to continue the chain and attach headers to the response.
Register it with http.middleware(mw) in the router pipe:
Log and CORS middleware — next(req) and .with_headers(#{...}).
// Feature: HTTP server — middleware via pipe
// Syntax: `fn mw(req, next) { ... return next(req) }` and
// `router |> http.middleware(mw)`
// When to use: logging, CORS, authentication, common headers —
// cross-cutting code shared across routes.
use std::http
// Middleware 1: log every request.
fn logger(req, next) {
print("[{req.method}] {req.path}")
return next(req)
}
// Middleware 2: add CORS headers to the response.
fn cors(req, next) {
return next(req).with_headers(#{
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE",
"Access-Control-Allow-Headers": "Content-Type",
})
}
fn api_health() {
return #{status: "ok"}
}
fn api_echo(req) {
return req.json()
}
let router = http.router()
|> http.get("/api/health", api_health)
|> http.post("/api/echo", api_echo)
|> http.middleware(logger)
|> http.middleware(cors)
http.serve(3003, router)
// expected when running:
// curl http://localhost:3003/api/health -> {"status":"ok"}
// curl -i http://localhost:3003/api/health -> CORS headers present
Requires the Zolo CLI/host — open in the playground or run locally.
Registration order matters: middlewares are executed in the order they appear in the pipe, before any route handler.
Challenge
Write a simple authentication middleware: if req.headers["Authorization"]
is nil, return http.response(401, "Unauthorized") without calling next.