forked from
karlseguin.tngl.sh/http.zig
An HTTP/1.1 server for zig
1const std = @import("std");
2const httpz = @import("httpz");
3
4const Io = std.Io;
5const Allocator = std.mem.Allocator;
6
7const PORT = 8803;
8
9// This example uses a custom dispatch method on our handler for greater control
10// in how actions are executed.
11
12pub fn main(init: std.process.Init) !void {
13 const allocator = init.gpa;
14
15 var handler = Handler{
16 .io = init.io,
17 };
18 var server = try httpz.Server(*Handler).init(init.io, allocator, .{ .address = .localhost(PORT) }, &handler);
19
20 defer server.deinit();
21
22 // ensures a clean shutdown, finishing off any existing requests
23 // see 09_shutdown.zig for how to to break server.listen with an interrupt
24 defer server.stop();
25
26 var router = try server.router(.{});
27
28 router.get("/", index, .{});
29 std.debug.print("listening http://localhost:{d}/\n", .{PORT});
30
31 // Starts the server, this is blocking.
32 try server.listen();
33}
34
35const Handler = struct {
36 io: Io,
37
38 // In addition to the special "notFound" and "uncaughtError" shown in example 2
39 // the special "dispatch" method can be used to gain more control over request handling.
40 pub fn dispatch(self: *Handler, action: httpz.Action(*Handler), req: *httpz.Request, res: *httpz.Response) !void {
41 // Our custom dispatch lets us add a log + timing for every request
42 // httpz supports middlewares, but in many cases, having a dispatch is good
43 // enough and is much more straightforward.
44
45 var start = Io.Timestamp.now(self.io, .awake);
46 // We don't _have_ to call the action if we don't want to. For example
47 // we could do authentication and set the response directly on error.
48 try action(self, req, res);
49
50 const elapsed = start.untilNow(self.io, .awake);
51 std.debug.print("ts={d} us={d} path={s}\n", .{ start.toSeconds(), elapsed.toMicroseconds(), req.url.path });
52 }
53};
54
55fn index(_: *Handler, _: *httpz.Request, res: *httpz.Response) !void {
56 res.body =
57 \\ If defied, the dispatch method will be invoked for every request with a matching route.
58 \\ It is up to dispatch to decide how/if the action should be called. While httpz
59 \\ supports middleware, most cases can be more easily and cleanly handled with
60 \\ a custom dispatch alone (you can always use both middlewares and a custom dispatch though).
61 \\
62 \\ Check out the console, our custom dispatch function times & logs each request.
63 ;
64}