aboutsummaryrefslogtreecommitdiff
path: root/src/http/handler.zig
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2026-06-06 07:57:50 +0200
committerNathan Reiner <nathan@nathanreiner.xyz>2026-06-06 07:57:50 +0200
commit51307d973255e32ec1440083dee383e8b2cd8878 (patch)
treedac0309c7abd40d2a3822fca3f7df0fd485e04f0 /src/http/handler.zig
parent17561c6be1e4fba11e243f2ac842ebe26fae7e60 (diff)
Implement static handler and synchronous server handling
Diffstat (limited to 'src/http/handler.zig')
-rw-r--r--src/http/handler.zig149
1 files changed, 0 insertions, 149 deletions
diff --git a/src/http/handler.zig b/src/http/handler.zig
deleted file mode 100644
index 2220fd0..0000000
--- a/src/http/handler.zig
+++ /dev/null
@@ -1,149 +0,0 @@
-const std = @import("std");
-
-const Response = @import("Response.zig");
-const Route = @import("Route.zig");
-const Parameter = @import("Parameter.zig");
-
-pub fn Context(comptime r: anytype) type {
- return struct {
- const route = Route.fromAny(r);
- const Params = Parameter.Struct(route);
-
- const Request = struct {
- base_request: *std.http.Server.Request,
- params: Params,
- arena: std.mem.Allocator,
- gpa: std.mem.Allocator,
- io: std.Io,
-
- /// Parses the body of the request and returns type `T`.
- /// The arena allocator will be used to do the parsing.
- pub fn json(self: @This(), T: type) !T {
- var buffer: [1024]u8 = undefined;
- var reader = std.json.Reader.init(self.arena, self.base_request.readerExpectNone(&buffer));
- return std.json.parseFromTokenSourceLeaky(T, self.arena, &reader, .{});
- }
- };
-
- const badRequest = struct {
- pub fn badRequest(_: Request) Response {
- return .with(.bad_request, .string("method does not exist"));
- }
- }.badRequest;
-
- get: *const fn (Request) Response = badRequest,
- post: *const fn (Request) Response = badRequest,
- delete: *const fn (Request) Response = badRequest,
- head: *const fn (Request) Response = badRequest,
- put: *const fn (Request) Response = badRequest,
- connect: *const fn (Request) Response = badRequest,
- options: *const fn (Request) Response = badRequest,
- trace: *const fn (Request) Response = badRequest,
- patch: *const fn (Request) Response = badRequest,
-
- pub fn handle(
- self: *const @This(),
- gpa: std.mem.Allocator,
- arena: std.mem.Allocator,
- io: std.Io,
- request: *std.http.Server.Request,
- ) Response {
- const req: Request = .{
- .base_request = request,
- .arena = arena,
- .gpa = gpa,
- .io = io,
- .params = Parameter.parse(Params, &route, request.head.target),
- };
-
- return (switch (request.head.method) {
- .GET => self.get,
- .POST => self.post,
- .DELETE => self.delete,
- .HEAD => self.head,
- .PUT => self.put,
- .CONNECT => self.connect,
- .OPTIONS => self.options,
- .TRACE => self.trace,
- .PATCH => self.patch,
- })(req);
- }
-
- pub fn interface(self: *const @This()) Interface {
- return .from(self, route);
- }
- };
-}
-
-pub const Interface = struct {
- route: Route,
- base: *const anyopaque,
- handler: *const fn (
- *const anyopaque,
- std.mem.Allocator,
- std.mem.Allocator,
- std.Io,
- *std.http.Server.Request,
- ) Response,
-
- pub fn from(instance: anytype, route: Route) @This() {
- const PtrT = @TypeOf(instance);
- const func = struct {
- pub fn handle(
- base: *const anyopaque,
- gpa: std.mem.Allocator,
- arena: std.mem.Allocator,
- io: std.Io,
- request: *std.http.Server.Request,
- ) Response {
- return @as(PtrT, @ptrCast(@alignCast(base))).handle(gpa, arena, io, request);
- }
- }.handle;
-
- return .{
- .base = @ptrCast(instance),
- .handler = func,
- .route = route,
- };
- }
-
- pub fn handle(
- self: *const @This(),
- gpa: std.mem.Allocator,
- arena: std.mem.Allocator,
- io: std.Io,
- request: std.http.Server.Request,
- ) Response {
- return self.handler(self.base, gpa, arena, io, request);
- }
-};
-
-test "interface" {
- const M = struct {
- const C = Context(.{ "api", "images", .id, "metadata" });
- const context: C = .{
- .post = post,
- .get = get,
- };
-
- const Query = struct {
- condition: []const u8,
- start: usize,
- length: usize,
- };
-
- fn post(request: C.Request) Response {
- const query = request.json(Query) catch return .with(.bad_request, .void);
- _ = query;
- _ = request.params.id;
-
- return .ok(.string(request.params.id.as([]const u8)));
- }
-
- fn get(request: C.Request) Response {
- return .ok(Response.Message.file(request.io, "./some/path.txt") catch return .with(.not_found, .void));
- }
- };
-
- _ = M.context.interface();
-}