Skip to content

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/html with the provided content.
  • http.redirect(path)302 Found to the given path.
  • http.response(status, body) — arbitrary status and body.

http.html, http.redirect and http.response with a custom status.

09-server-response-helpers.zolo
// 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.

10-server-multi-worker.zolo
// 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.

enespt-br