From 1d6e34388d9d792fd184c8b9e0fb11fb9b7e14f9 Mon Sep 17 00:00:00 2001 From: Nathan Reiner Date: Sat, 6 Jun 2026 10:35:14 +0200 Subject: api: add example implementations --- src/api/hello-body.zig | 20 ++++++++++++++++++++ src/api/hello-json.zig | 15 +++++++++++++++ src/api/hello-param.zig | 14 ++++++++++++++ src/api/root.zig | 17 ++++++++++++++++- src/http/Response.zig | 17 +++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/api/hello-body.zig create mode 100644 src/api/hello-json.zig create mode 100644 src/api/hello-param.zig diff --git a/src/api/hello-body.zig b/src/api/hello-body.zig new file mode 100644 index 0000000..2e5a09e --- /dev/null +++ b/src/api/hello-body.zig @@ -0,0 +1,20 @@ +const http = @import("http"); +const Context = http.handler.Context; +const Response = http.Response; + +const Ctx = Context(.{"hello-body"}); +pub const ctx: Ctx = .{ + .post = post, +}; + +const Body = struct { + value: usize, +}; + +fn post(request: Ctx.Request) Response { + const body = request.json(Body) catch return .bad_request(.void); + + return .ok_or_error(.json(request.arena, .{ + .value = body.value, + })); +} diff --git a/src/api/hello-json.zig b/src/api/hello-json.zig new file mode 100644 index 0000000..7c96c29 --- /dev/null +++ b/src/api/hello-json.zig @@ -0,0 +1,15 @@ +const http = @import("http"); +const Context = http.handler.Context; +const Response = http.Response; + +const Ctx = Context(.{ "hello-json" }); +pub const ctx: Ctx = .{ + .get = get, +}; + +fn get(request: Ctx.Request) Response { + return .ok_or_error(.json(request.arena, .{ + .value = 42, + .message = "Hello, Json!", + })); +} diff --git a/src/api/hello-param.zig b/src/api/hello-param.zig new file mode 100644 index 0000000..ba798af --- /dev/null +++ b/src/api/hello-param.zig @@ -0,0 +1,14 @@ +const http = @import("http"); +const Context = http.handler.Context; +const Response = http.Response; + +const Ctx = Context(.{ "hello-param", .value }); +pub const ctx: Ctx = .{ + .get = get, +}; + +fn get(request: Ctx.Request) Response { + const value = request.params.value.as(usize) catch return .bad_request(.string("parameter needs to be an int")); + + return .ok_or_error(.json(request.arena, .{ .value = value, })); +} diff --git a/src/api/root.zig b/src/api/root.zig index 7acd953..7570a76 100644 --- a/src/api/root.zig +++ b/src/api/root.zig @@ -6,7 +6,22 @@ const std = @import("std"); const http = @import("http"); const Interface = http.handler.Interface; -pub const interfaces: []const Interface = &.{}; +const modules = .{ + @import("hello-json.zig"), + @import("hello-param.zig"), + @import("hello-body.zig"), +}; + +pub const interfaces: []const Interface = ifs: { + var ifs: []const Interface = &.{}; + + for (modules) |module| { + const interface: []const Interface = &.{ module.ctx.interface() }; + ifs = ifs ++ interface; + } + + break :ifs ifs; +}; test { _ = std.testing.refAllDecls(@This()); diff --git a/src/http/Response.zig b/src/http/Response.zig index 8d10992..d54792b 100644 --- a/src/http/Response.zig +++ b/src/http/Response.zig @@ -5,6 +5,15 @@ pub const Message = union(enum) { static: []const u8, streaming: std.Io.File, + pub fn json(arena: std.mem.Allocator, value: anytype) !Message { + var allocating: std.Io.Writer.Allocating = .init(arena); + + var jsonify: std.json.Stringify = .{ .writer = &allocating.writer }; + try jsonify.write(value); + + return .string(try allocating.toOwnedSlice()); + } + pub fn string(content: []const u8) Message { return .{ .static = content }; } @@ -27,6 +36,14 @@ pub fn ok(message: Message) @This() { return with(.ok, message); } +pub fn ok_or_error(message: anyerror!Message) @This() { + return ok(message catch return with(.internal_server_error, .void)); +} + +pub fn bad_request(message: Message) @This() { + return with(.bad_request, message); +} + pub fn send( self: *const @This(), io: std.Io, -- cgit v1.2.3-70-g09d2