En esta página
HTTP Server and Web Applications
Zolo includes a native HTTP server in std::http. It can serve APIs, plain text and Verniz View values from the same router.
Quick start with a View¶
use std::http
use std::html::{document, head, title, body, h1, p, View}
fn home(_req) -> View {
<document lang="en">
<head><title>Zolo web</title></head>
<body>
<h1>Hello from Zolo</h1>
<p>The route returned a View.</p>
</body>
</document>
}
let app = http.router()
|> http.get("/", home)
http.serve(3000, app)The server renders a returned View and selects the HTML content type. Strings become plain text, maps become JSON, and nil becomes a 204 response.
Router and routes¶
Pipe-style route functions return the router, which makes composition explicit:
let app = http.router()
|> http.get("/health", health)
|> http.get("/users/:id", show_user)
|> http.post("/users", create_user)
|> http.put("/users/:id", replace_user)
|> http.delete("/users/:id", delete_user)
|> http.middleware(logger)| Function | Purpose |
|---|---|
http.router() |
Create an empty router |
http.get/post/put/delete(router, path, handler) |
Register a route and return the router |
http.middleware(router, fn) |
Append middleware |
http.server() |
Create a fluent server/router builder |
http.serve(port, router, workers: n) |
Start the server |
The router object also exposes fluent .get, .post, .put, .delete, .patch and .use methods. Paths accept both :id and {id} captures.
Request data¶
Handlers receive a request with the method, path, headers, body, query values and route captures.
fn show_user(req) {
let id = req.params.id
let verbose = req.query.verbose ?? "0"
return #{
"id": id,
"verbose": verbose,
"method": req.method,
}
}
fn create_user(req) {
let payload = req.json()
return http.created("created {payload.name}")
}Use req.body for the raw body and req.json() for JSON. Invalid or missing input should become an explicit response from your handler rather than an unchecked assumption.
Responses¶
A handler may return a simple value or an explicit response:
| Value | Result |
|---|---|
View |
Rendered HTML |
str, number or boolean |
Plain-text response |
| Map/table | JSON response |
nil |
204 No Content |
http.response(status, body, headers) |
Fully explicit response |
http.ok(body) / http.created(body) |
200 / 201 helpers |
http.no_content() |
204 helper |
http.bad_request(body) / http.not_found(body) |
400 / 404 helpers |
http.redirect(url) |
302 with Location |
http.html(body) |
Explicit HTML response |
Response objects support fluent header methods. Prefer returning a View directly when the body is already Verniz content.
Middleware and workers¶
Middleware receives req and next:
fn logger(req, next) {
print("[{req.method}] {req.path}")
return next(req)
}Pass workers: to http.serve for production concurrency. Each worker reruns top-level initialization; place process-wide startup in on boot and per-worker setup in on worker.
http.serve(3000, app, workers: 4)During zolo dev, web mode intentionally uses one live VM so source can be swapped in place.
Request and cookie effects¶
std::web wraps std::http routes with Request and Cookies effects. Deep functions can read the current request or set a cookie without threading req through every call.
use std::web
fn home(_req) with Request -> str {
return "path: {perform Request::path()}"
}
let app = web.router() |> web.get("/", home)
web.serve(3000, app)Secure cookies are encrypted by default through Cookie.new; signed and public constructors make weaker visibility explicit. Configure ZOLO_SECRET_KEY before production. This std::web effect/cookie layer is currently VM-only; the lower-level HTTP server and Verniz run on LLVM and Cranelift too.
Live development¶
Run a web entry with:
zolo dev src/main.zoloWhen the program reaches http.serve, the CLI enables web mode automatically. Successful saves swap the live VM, notify tabs over SSE, revalidate the current route and morph the DOM. Compile errors keep the last good app serving and appear in the browser overlay.
Continue with Web Development and Development Workflow.