Routing
Tokamak includes an Express-inspired router with support for path parameters, wildcards, and nested routes.
Basic Routes
Define routes with HTTP method shortcuts:
zig
const routes: []const tk.Route = &.{
.get("/", hello),
.post("/users", createUser),
.put("/users/:id", updateUser),
.delete("/users/:id", deleteUser),
};Path Parameters
Path parameters are automatically extracted and passed to handlers:
zig
const routes: []const tk.Route = &.{
.get("/hello/:name", helloName),
.get("/users/:id/posts/:postId", getUserPost),
};
fn helloName(arena: std.mem.Allocator, name: []const u8) ![]const u8 {
return std.fmt.allocPrint(arena, "Hello {s}", .{name});
}
fn getUserPost(id: []const u8, postId: []const u8) !Post {
// id and postId are automatically injected
return db.getPost(id, postId);
}TIP
Tokamak supports up to 16 path parameters per route.
Wildcards
Use * for wildcard matching:
zig
const routes: []const tk.Route = &.{
.get("/api/*", apiHandler),
.get("/assets/*", tk.static.dir("assets", .{})),
};Nested Routes
Group routes with common prefixes:
zig
const routes: []const tk.Route = &.{
.group("/api", &.{
.group("/v1", &.{
.get("/users", getUsers),
.post("/users", createUser),
}),
.group("/v2", &.{
.get("/users", getUsersV2),
}),
}),
};Router DSL
For more organized routing, use Route.router(T) with a struct:
zig
const routes: []const tk.Route = &.{
.group("/api", &.{ .router(api) }),
};
const api = struct {
pub fn @"GET /"() []const u8 {
return "API Home";
}
pub fn @"GET /:name"(arena: std.mem.Allocator, name: []const u8) ![]const u8 {
return std.fmt.allocPrint(arena, "Hello {s}", .{name});
}
pub fn @"POST /users"(body: User) !User {
// body is automatically parsed from JSON
return db.create(body);
}
};Query Strings
Add a ? suffix to the path to enable query string parsing:
zig
const routes: []const tk.Route = &.{
.get("/search?", search),
};
fn search(query: SearchQuery) ![]SearchResult {
// query.term, query.limit, query.offset are automatically parsed
return db.search(query.term, query.limit, query.offset);
}
const SearchQuery = struct {
term: []const u8,
limit: ?u32 = null,
offset: ?u32 = null,
};Request: GET /search?term=zig&limit=10&offset=20
Request Body
POST/PUT routes automatically parse JSON bodies:
zig
fn createUser(body: User) !User {
// body is automatically deserialized
return db.save(body);
}Use .post0() to skip body parsing:
zig
const routes: []const tk.Route = &.{
.post0("/webhook", handleWebhook),
};
fn handleWebhook(req: *tk.Request) !void {
// Manually read the body
const body = try req.readAll();
}Route Inspection
Routes are hierarchical and introspectable, making it easy to generate documentation or OpenAPI specs:
zig
// Tokamak includes basic Swagger support
const routes: []const tk.Route = &.{
tk.swagger(.{}),
.get("/users", getUsers),
};