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 = 8807;
8
9// This example shows more advanced routing example, namely route groups
10// and route configuration. (The previous example, with middleware, also showed
11// per-route configuration for middleware specifically).
12
13pub fn main(init: std.process.Init) !void {
14 const allocator = init.gpa;
15
16 var default_handler = Handler{
17 .io = init.io,
18 .log = true,
19 };
20
21 var nolog_handler = Handler{
22 .io = init.io,
23 .log = false,
24 };
25
26 var server = try httpz.Server(*Handler).init(init.io, allocator, .{ .address = .localhost(PORT) }, &default_handler);
27
28 defer server.deinit();
29
30 // ensures a clean shutdown, finishing off any existing requests
31 // see 09_shutdown.zig for how to to break server.listen with an interrupt
32 defer server.stop();
33
34 var router = try server.router(.{});
35
36 router.get("/", index, .{});
37
38 // We can define a dispatch function per-route. This will be used instead of Handler.dispatch
39 // But, sadly, every dispatch method must have the same signature (they must all accept the same type of action)
40 router.get("/page1", page1, .{ .dispatcher = Handler.infoDispatch });
41
42 // We can define a handler instance per-route. This will be used instead of the
43 // handler instance passed to the init method above.
44 router.get("/page2", page2, .{ .handler = &nolog_handler });
45
46 std.debug.print("listening http://localhost:{d}/\n", .{PORT});
47
48 // Starts the server, this is blocking.
49 try server.listen();
50}
51
52const Handler = struct {
53 io: Io,
54 log: bool,
55
56 // special dispatch set in the info route
57 pub fn infoDispatch(h: *Handler, action: httpz.Action(*Handler), req: *httpz.Request, res: *httpz.Response) !void {
58 return action(h, req, res);
59 }
60
61 pub fn dispatch(h: *Handler, action: httpz.Action(*Handler), req: *httpz.Request, res: *httpz.Response) !void {
62 try action(h, req, res);
63 if (h.log) {
64 std.debug.print("ts={d} path={s} status={d}\n", .{ Io.Timestamp.now(h.io, .real), req.url.path, res.status });
65 }
66 }
67};
68
69fn index(_: *Handler, _: *httpz.Request, res: *httpz.Response) !void {
70 res.content_type = .HTML;
71 res.body =
72 \\<!DOCTYPE html>
73 \\ <p>It's possible to define a custom dispatch method, custom handler instance and/or custom middleware per-route.
74 \\ <p>It's also possible to create a route group, which is a group of routes who share a common prefix and/or a custom configration.
75 \\ <ul>
76 \\ <li><a href="/page1">page with custom dispatch</a>
77 \\ <li><a href="/page2">page with custom handler</a>
78 ;
79}
80
81fn page1(_: *Handler, _: *httpz.Request, res: *httpz.Response) !void {
82 // Called with a custom config which specified a custom dispatch method
83 res.body =
84 \\ Accessing this endpoint will NOT generate a log line in the console,
85 \\ because a custom dispatch method is used
86 ;
87}
88
89fn page2(_: *Handler, _: *httpz.Request, res: *httpz.Response) !void {
90 // Called with a custom config which specified a custom handler instance
91 res.body =
92 \\ Accessing this endpoint will NOT generate a log line in the console,
93 \\ because a custom handler instance is used
94 ;
95}