Responses and Workers
By default, returning a string from a handler produces 200 text/plain and returning
a map produces 200 application/json. For other scenarios there are three helpers:
http.html(str)—200 text/htmlwith the provided content.http.redirect(path)—302 Foundto the given path.http.response(status, body)— arbitrary status and body.
http.html, http.redirect and http.response with a custom status.
// Feature: HTTP server — `http.response`, `http.html`, `http.redirect`
// Syntax: handler returns a helper built from `http.*`.
// When to use: custom status, explicit content-type, redirects.
use std::json
use std::http
// Plain string -> 200 text/plain.
fn handle_root(_req) {
return "Hello from Zolo!"
}
// Map -> 200 application/json.
fn handle_json(_req) {
return #{message: "Hello", language: "Zolo"}
}
// Raw HTML with the correct Content-Type.
fn handle_html(_req) {
return http.html("<h1>Hello from Zolo!</h1>")
}
// 302 redirect.
fn handle_redirect(_req) {
return http.redirect("/")
}
// Custom status + body.
fn handle_status(_req) {
return http.response(201, "Created!")
}
let app = http.router()
|> http.get("/", handle_root)
|> http.get("/json", handle_json)
|> http.get("/html", handle_html)
|> http.get("/redirect", handle_redirect)
|> http.get("/status", handle_status)
http.serve(3004, app)
// expected when running:
// curl http://localhost:3004/json -> {"message":"Hello","language":"Zolo"}
// curl http://localhost:3004/html -> <h1>Hello from Zolo!</h1>
// curl -i http://localhost:3004/status -> HTTP/1.1 201 Created
Requires the Zolo CLI/host — open in the playground or run locally.
To handle multiple simultaneous requests without one blocking another,
http.workers(N) initializes N independent VMs that share the same route
registry and serve requests in round-robin:
http.workers(4) before http.serve for request-level parallelism.
// Feature: HTTP server — multiple workers
// Syntax: `http.workers(N)` before `http.serve(...)`.
// When to use: parallelism for CPU-bound requests; each worker is an
// isolated VM running the same route registry.
use std::http
@get("/")
fn index() {
return "Hello from a worker!"
}
@get("/heavy")
fn heavy() {
// Some arbitrary work; in production, with multiple workers, concurrent
// requests do not block one another.
var acc = 0
for i in 1..=10000 {
acc = acc + i
}
return #{sum: acc}
}
// Spin up 4 workers (each with its own LuaState) serving round-robin.
http.workers(4)
http.serve(3005)
// expected when running:
// curl http://localhost:3005/ -> Hello from a worker!
// ab -n 1000 -c 50 http://localhost:3005/heavy (load test)
Requires the Zolo CLI/host — open in the playground or run locally.
Each worker runs in its own LuaState, so there is no shared state
between them — which eliminates data races but also means that mutations
to global variables in one worker are not visible in the others.
Challenge
Add a /status route that returns http.response(503, "Unavailable") and
verify with curl -i that the HTTP status code is correct.
See also