Quick Start
This guide walks you through building a small zzz application with routes, middleware, and JSON responses.
Hello World
Section titled “Hello World”-
Create a new project
Terminal window zzz new hello_zzzcd hello_zzz -
Open
src/main.zigand replace its contents with:const std = @import("std");const zzz = @import("zzz");fn index(ctx: *zzz.Context) !void {ctx.text(.ok, "Hello from zzz!");}const App = zzz.Router.define(.{.middleware = &.{zzz.logger},.routes = &.{zzz.Router.get("/", index),},});pub fn main() !void {var gpa = std.heap.GeneralPurposeAllocator(.{}){};defer _ = gpa.deinit();var server = zzz.Server.init(gpa.allocator(), .{.port = 4000,}, &App.handler);std.log.info("Listening on http://127.0.0.1:4000", .{});try server.listen(std.io.defaultIo());} -
Run it
Terminal window zig build runVisit
http://127.0.0.1:4000— you should see “Hello from zzz!”.
Adding middleware
Section titled “Adding middleware”zzz ships with 20 built-in middleware. Let’s add a few common ones:
const App = zzz.Router.define(.{ .middleware = &.{ zzz.errorHandler(.{ .show_details = true }), zzz.logger, zzz.requestId(.{}), zzz.cors(.{ .allow_origins = &.{"*"} }), zzz.bodyParser(.{}), zzz.staticFiles(.{ .root = "public", .prefix = "/static" }), }, .routes = &.{ zzz.Router.get("/", index), },});Middleware runs in the order listed — put error handling first so it catches everything downstream.
JSON routes
Section titled “JSON routes”Add a route that returns JSON:
fn getUser(ctx: *zzz.Context) !void { const user = .{ .id = 1, .name = "Alice", .email = "alice@example.com", }; try ctx.json(.ok, user);}
fn createUser(ctx: *zzz.Context) !void { const body = try ctx.parseBody(struct { name: []const u8, email: []const u8, }); // ... save to database ... try ctx.json(.created, body);}Wire them into your router:
.routes = &.{ zzz.Router.get("/", index), zzz.Router.get("/users/:id", getUser), zzz.Router.post("/users", createUser),},RESTful resources
Section titled “RESTful resources”For standard CRUD, use Router.resource to generate all routes at once:
.routes = &.{ zzz.Router.resource("/posts", .{ .index = listPosts, .show = showPost, .create = createPost, .update = updatePost, .delete_handler = deletePost, }),},This generates GET /posts, GET /posts/:id, POST /posts, PUT /posts/:id, and DELETE /posts/:id.
Scoped routes with auth
Section titled “Scoped routes with auth”Group routes under a prefix with shared middleware:
.routes = &.{ zzz.Router.get("/", index),
zzz.Router.scope("/api", .{ .middleware = &.{ zzz.bearerAuth(.{ .validate = &myValidator }) }, }, &.{ zzz.Router.get("/me", currentUser), zzz.Router.resource("/posts", .{ .index = listPosts, .create = createPost, }), }),},Next steps
Section titled “Next steps”You now have a working zzz application with routing, middleware, and JSON. From here:
- Learn about Routing in depth
- Add a Database
- Set up Background Jobs
- Add WebSocket Channels
- Use the Template Engine for HTML views