forked from
karlseguin.tngl.sh/http.zig
An HTTP/1.1 server for zig
1const std = @import("std");
2const httpz = @import("httpz");
3const Allocator = std.mem.Allocator;
4
5const PORT = 8801;
6
7// This example demonstrates basic httpz usage, with focus on using the
8// httpz.Request and httpz.Response objects.
9
10pub fn main(init: std.process.Init) !void {
11 const allocator = init.gpa;
12
13 // We pass a "void" handler. This is the simplest, but limits what we can do
14 // The last parameter is an instance of our handler. Since we have
15 // a void handler, we pass a void value: i.e. {}.
16 var server = try httpz.Server(void).init(init.io, allocator, .{
17 .address = .localhost(PORT),
18 .request = .{
19 // httpz has a number of tweakable configuration settings (see readme)
20 // by default, it won't read form data. We need to configure a max
21 // field count (since one of our examples reads form data)
22 .max_form_count = 20,
23 },
24 }, {});
25 defer server.deinit();
26
27 // ensures a clean shutdown, finishing off any existing requests
28 // see 09_shutdown.zig for how to to break server.listen with an interrupt
29 defer server.stop();
30
31 var router = try server.router(.{});
32
33 // Register routes. The last parameter is a Route Config. For these basic
34 // examples, we aren't using it.
35 // Other support methods: post, put, delete, head, trace, options and all
36 router.get("/", index, .{});
37 router.get("/hello", hello, .{});
38 router.get("/json/hello/:name", json, .{});
39 router.get("/writer/hello/:name", writer, .{});
40 router.get("/metrics", metrics, .{});
41 router.get("/form_data", formShow, .{});
42 router.post("/form_data", formPost, .{});
43 router.get("/explicit_write", explicitWrite, .{});
44
45 std.debug.print("listening http://localhost:{d}/\n", .{PORT});
46
47 // Starts the server, this is blocking.
48 try server.listen();
49}
50
51fn index(_: *httpz.Request, res: *httpz.Response) !void {
52 res.body =
53 \\<!DOCTYPE html>
54 \\ <ul>
55 \\ <li><a href="/hello?name=Teg">Querystring + text output</a>
56 \\ <li><a href="/writer/hello/Ghanima">Path parameter + serialize json object</a>
57 \\ <li><a href="/json/hello/Duncan">Path parameter + json writer</a>
58 \\ <li><a href="/metrics">Internal metrics</a>
59 \\ <li><a href="/form_data">Form Data</a>
60 \\ <li><a href="/explicit_write">Explicit Write</a>
61 ;
62}
63
64fn hello(req: *httpz.Request, res: *httpz.Response) !void {
65 const query = try req.query();
66 const name = query.get("name") orelse "stranger";
67
68 // Could also see res.writer(), see the writer endpoint for an example
69 res.body = try std.fmt.allocPrint(res.arena, "Hello {s}", .{name});
70}
71
72fn json(req: *httpz.Request, res: *httpz.Response) !void {
73 const name = req.param("name").?;
74
75 // the last parameter to res.json is an std.json.StringifyOptions
76 try res.json(.{ .hello = name }, .{});
77}
78
79fn writer(req: *httpz.Request, res: *httpz.Response) !void {
80 res.content_type = httpz.ContentType.JSON;
81
82 const name = req.param("name").?;
83
84 try std.json.Stringify.value(
85 .{ .name = name },
86 .{ .whitespace = .indent_4 },
87 res.writer(),
88 );
89}
90
91fn metrics(_: *httpz.Request, res: *httpz.Response) !void {
92 // httpz exposes some prometheus-style metrics
93 return httpz.writeMetrics(res.writer());
94}
95
96fn formShow(_: *httpz.Request, res: *httpz.Response) !void {
97 res.body =
98 \\ <html>
99 \\ <form method=post>
100 \\ <p><input name=name value=goku></p>
101 \\ <p><input name=power value=9001></p>
102 \\ <p><input type=submit value=submit></p>
103 \\ </form>
104 ;
105}
106
107fn formPost(req: *httpz.Request, res: *httpz.Response) !void {
108 var it = (try req.formData()).iterator();
109
110 res.content_type = .TEXT;
111
112 const w = res.writer();
113 while (it.next()) |kv| {
114 try w.print("{s}={s}\n", .{ kv.key, kv.value });
115 }
116}
117
118fn explicitWrite(_: *httpz.Request, res: *httpz.Response) !void {
119 res.body =
120 \\ There may be cases where your response is tied to data which
121 \\ required cleanup. If `res.arena` and `res.writer()` can't solve
122 \\ the issue, you can always call `res.write()` explicitly
123 ;
124 return res.write();
125}