An HTTP/1.1 server for zig
0

Configure Feed

Select the types of activity you want to include in your feed.

http.zig / examples / 02_handler.zig
3.4 kB 91 lines
1const std = @import("std"); 2const httpz = @import("httpz"); 3const Allocator = std.mem.Allocator; 4 5const PORT = 8802; 6 7// This example demonstrates using a custom Handler. It shows how to have 8// global state (here we show a counter, but it could be a more complex struct 9// including things such as a DB pool) and how to define not found and error 10// handlers. 11 12pub fn main(init: std.process.Init) !void { 13 const allocator = init.gpa; 14 15 // We specify our "Handler" and, as the last parameter to init, pass an 16 // instance of it. 17 var handler = Handler{}; 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 // Register routes. 29 30 router.get("/", index, .{}); 31 router.get("/hits", hits, .{}); 32 router.get("/error", @"error", .{}); 33 34 std.debug.print("listening http://localhost:{d}/\n", .{PORT}); 35 36 // Starts the server, this is blocking. 37 try server.listen(); 38} 39 40const Handler = struct { 41 _hits: usize = 0, 42 43 // If the handler defines a special "notFound" function, it'll be called 44 // when a request is made and no route matches. 45 pub fn notFound(_: *Handler, _: *httpz.Request, res: *httpz.Response) !void { 46 res.status = 404; 47 res.body = "NOPE!"; 48 } 49 50 // If the handler defines the special "uncaughtError" function, it'll be 51 // called when an action returns an error. 52 // Note that this function takes an additional parameter (the error) and 53 // returns a `void` rather than a `!void`. 54 pub fn uncaughtError(_: *Handler, req: *httpz.Request, res: *httpz.Response, err: anyerror) void { 55 std.debug.print("uncaught http error at {s}: {}\n", .{ req.url.path, err }); 56 57 // Alternative to res.content_type = .TYPE 58 // useful for dynamic content types, or content types not defined in 59 // httpz.ContentType 60 res.headers.add("content-type", "text/html; charset=utf-8"); 61 62 res.status = 505; 63 res.body = "<!DOCTYPE html>(╯°□°)╯︵ ┻━┻"; 64 } 65}; 66 67fn index(_: *Handler, _: *httpz.Request, res: *httpz.Response) !void { 68 res.body = 69 \\<!DOCTYPE html> 70 \\ <p>Except in very simple cases, you'll want to use a custom Handler. 71 \\ <p>A custom Handler is how you share app-specific data with your actions (like a DB pool) 72 \\ and define a custom not found and error function. 73 \\ <p>Other examples show more advanced things you can do with a custom Handler. 74 \\ <ul> 75 \\ <li><a href="/hits">Shared global hit counter</a> 76 \\ <li><a href="/not_found">Custom not found handler</a> 77 \\ <li><a href="/error">Custom error handler</a> 78 ; 79} 80 81pub fn hits(h: *Handler, _: *httpz.Request, res: *httpz.Response) !void { 82 const count = @atomicRmw(usize, &h._hits, .Add, 1, .monotonic); 83 84 // @atomicRmw returns the previous version so we need to +1 it 85 // to display the count includin this hit 86 return res.json(.{ .hits = count + 1 }, .{}); 87} 88 89fn @"error"(_: *Handler, _: *httpz.Request, _: *httpz.Response) !void { 90 return error.ActionError; 91}