1
0
Fork 0
mirror of https://github.com/zigzap/zap.git synced 2025-10-20 23:24:09 +00:00
zap/src/router.zig
2024-01-24 13:59:36 +01:00

77 lines
2.1 KiB
Zig

const std = @import("std");
const zap = @import("zap.zig");
const Allocator = std.mem.Allocator;
const RouterError = error{
AlreadyExists,
EmptyPath,
};
// inline closure for RequestFn with self argument
pub inline fn RequestHandler(self: anytype, func: *const fn (@TypeOf(self), zap.Request) void) *const fn (zap.Request) void {
return (opaque {
var hidden_self: @TypeOf(self) = undefined;
var hidden_func: *const fn (@TypeOf(self), zap.Request) void = undefined;
pub fn init(h_self: @TypeOf(self), h_func: *const fn (@TypeOf(self), zap.Request) void) *const @TypeOf(run) {
hidden_self = h_self;
hidden_func = h_func;
return &run;
}
fn run(req: zap.Request) void {
hidden_func(hidden_self, req);
}
}).init(self, func);
}
pub const RouterOptions = struct {
not_found: ?zap.HttpRequestFn = null,
};
pub const Router = struct {
const Self = @This();
routes: std.StringHashMap(zap.HttpRequestFn),
not_found: ?zap.HttpRequestFn,
pub fn init(allocator: Allocator, options: RouterOptions) Self {
return .{
.routes = std.StringHashMap(zap.HttpRequestFn).init(allocator),
.not_found = options.not_found,
};
}
pub fn deinit(self: *Self) void {
self.routes.deinit();
}
pub fn handle_func(self: *Self, path: []const u8, h: zap.HttpRequestFn) !void {
if (path.len == 0) {
return RouterError.EmptyPath;
}
const route = self.routes.get(path);
if (route != null) {
return RouterError.AlreadyExists;
}
try self.routes.put(path, h);
}
pub fn serve(self: *Self, r: zap.Request) void {
var route = self.routes.get(r.path.?);
if (route) |handler| {
handler(r);
} else if (self.not_found) |handler| {
// not found handler
handler(r);
} else {
// default 404 output
r.setStatus(.not_found);
r.sendBody("404 Not Found") catch return;
}
}
};