### Build and Run Zig Example Source: https://github.com/zigzap/zap/blob/master/README.md Use 'zig build [EXAMPLE]' to build and './zig-out/bin/[EXAMPLE]' to run a specific example. Replace [EXAMPLE] with the desired example name. ```shell $ zig build [EXAMPLE] $ ./zig-out/bin/[EXAMPLE] ``` -------------------------------- ### Build and Run Zig Example (Specific) Source: https://github.com/zigzap/zap/blob/master/README.md Build and run the 'hello' example using 'zig build hello' and then execute it with './zig-out/bin/hello'. ```shell $ zig build hello $ ./zig-out/bin/hello ``` -------------------------------- ### Hello World Example in Zig Source: https://github.com/zigzap/zap/blob/master/README.md A basic 'Hello World' example using ⚡zap⚡. It defines an on_request handler to send an HTML response and starts an HTTP listener on port 3000. Ensure 'zap' is imported. ```zig const std = @import("std"); const zap = @import("zap"); fn on_request(r: zap.Request) !void { if (r.path) |the_path| { std.debug.print("PATH: {s}\n", .{the_path}); } if (r.query) |the_query| { std.debug.print("QUERY: {s}\n", .{the_query}); } r.sendBody("

Hello from ZAP!!!

") catch return; } pub fn main() !void { var listener = zap.HttpListener.init(.{ .port = 3000, .on_request = on_request, .log = true, }); try listener.listen(); std.debug.print("Listening on 0.0.0.0:3000\n", .{}); // start worker threads zap.start(.{ .threads = 2, .workers = 2, }); } ``` -------------------------------- ### Run Zig Routes Example Source: https://github.com/zigzap/zap/blob/master/README.md Build and run the 'routes' example by executing 'zig build run-routes'. ```shell $ zig build run-routes ``` -------------------------------- ### Run Zig Example Without Building Source: https://github.com/zigzap/zap/blob/master/README.md To run an example like 'routes' without generating a separate executable, use 'zig build run-[EXAMPLE]'. ```shell $ zig build run-[EXAMPLE] ``` -------------------------------- ### Complete build.zig.zon Example Source: https://github.com/zigzap/zap/blob/master/doc/release-template.md A full example of a build.zig.zon file demonstrating how to include ZAP among other dependencies. Ensure the ZAP dependency details are correctly specified. ```zig .{ .name = "My example project", .version = "0.0.1", .dependencies = .{ // zap {tag} .zap = .{ .url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz", .hash = "{hash}", }, .paths = .{ "", } } } ``` -------------------------------- ### Run Hello Example with Zig Source: https://github.com/zigzap/zap/blob/master/README.md Clones the Zap repository, navigates into the directory, and runs the 'hello' example using the Zig build system. This is a quick way to test the framework. ```shell git clone https://github.com/zigzap/zap.git cd zap zig build run-hello # open http://localhost:3000 in your browser ``` -------------------------------- ### HTTP Server Example in C Source: https://github.com/zigzap/zap/blob/master/facil.io/README.md Demonstrates setting up an HTTP server with facil.io, handling requests, setting cookies, headers, and sending responses. Requires including 'http.h'. ```c #include "http.h" /* the HTTP facil.io extension */ // We'll use this callback in `http_listen`, to handles HTTP requests void on_request(http_s *request); // These will contain pre-allocated values that we will use often FIOBJ HTTP_X_DATA; // Listen to HTTP requests and start facil.io int main(int argc, char const **argv) { // allocating values we use often HTTP_X_DATA = fiobj_str_new("X-Data", 6); // listen on port 3000 and any available network binding (NULL == 0.0.0.0) http_listen("3000", NULL, .on_request = on_request, .log = 1); // start the server facil_run(.threads = 1); // deallocating the common values fiobj_free(HTTP_X_DATA); } // Easy HTTP handling void on_request(http_s *request) { http_set_cookie(request, .name = "my_cookie", .name_len = 9, .value = "data", .value_len = 4); http_set_header(request, HTTP_HEADER_CONTENT_TYPE, http_mimetype_find("txt", 3)); http_set_header(request, HTTP_X_DATA, fiobj_str_new("my data", 7)); http_send_body(request, "Hello World!\r\n", 14); } ``` -------------------------------- ### HTTP Parameters Example in Zig Source: https://github.com/zigzap/zap/blob/master/README.md A simple example that sends itself query parameters of various supported types. This helps in understanding how Zap handles different parameter formats. ```zig const std = @import("std"); const zap = @import("zap"); pub fn main() !void { var app = try zap.Zap.init(); app.router.add("/params", "GET", "/params", fn(r: zap.Request) !zap.Response { // Example of accessing parameters const name = r.params.get("name"); const age = r.params.get("age"); const is_active = r.params.get("active"); var response_body = std.fmt.allocPrint(std.heap.page_allocator, "Name: {s}, Age: {s}, Active: {s}\\n", .{ name.?, // Use .? for optional strings age.?, is_active.?, }); defer std.heap.page_allocator.free(response_body); return zap.Response.init(200, response_body); }); // To test, you would typically make a request like: // http://localhost:8080/params?name=Test&age=30&active=true try app.listen(8080); } ``` -------------------------------- ### Mustache Templating Example in Zig Source: https://github.com/zigzap/zap/blob/master/README.md A simple example demonstrating the integration and usage of Mustache templating with Zap. This allows for dynamic HTML generation using templates. ```zig const std = @import("std"); const zap = @import("zap"); const mustache = @import("mustache"); // Assuming mustache library is available pub fn main() !void { var app = try zap.Zap.init(); // Load your Mustache template (e.g., from a file or string) const template_string = "

Hello, {{name}}!

"; var template = try mustache.parse(template_string); defer template.deinit(); app.router.add("/", "GET", "/", fn(r: zap.Request) !zap.Response { var writer = std.heap.page_allocator.writer(); var buffer: [1024]u8 = undefined; var string_writer = std.io.fixedBufferStream(&buffer).writer(); const data = std.json.Value.object(.{ .{ .key = "name", .value = std.json.Value.string("World"), }, }); try template.render(&string_writer, data); const rendered_html = string_writer.toOwnedSlice(); defer std.heap.page_allocator.free(rendered_html); return zap.Response.init(200, rendered_html); }); try app.listen(8080); } ``` -------------------------------- ### Sending a File with Compression Headers in Zig Source: https://github.com/zigzap/zap/blob/master/README.md Provides a simple example of how to send a file response, correctly handling compression headers like `Accept-Encoding` to optimize delivery. ```zig const std = @import("std"); const zap = @import("zap"); pub fn main() !void { var app = try zap.Zap.init(); // Assuming 'path/to/your/file.txt' exists app.router.add("/download", "GET", "/download", fn(r: zap.Request) !zap.Response { return zap.Response.sendFile(r, "path/to/your/file.txt"); }); try app.listen(8080); } ``` -------------------------------- ### Basic Zap App with Endpoint Source: https://github.com/zigzap/zap/blob/master/README.md Demonstrates the basic usage of zap.App with a simple Endpoint. This example shows how to set up a minimal application context and define a basic URL slug with a callback. ```zig const zap = @import("zap"); const BasicEndpoint = struct { const Self = @This(); pub fn handle(req: zap.http.Request, app_context: zap.App.Context) !void { _ = req; _ = app_context; return zap.http.Response.new(200, "Hello, World!"); } }; pub fn main() !void { var app = try zap.App.init(.{}); defer app.deinit(); app.addEndpoint("/", BasicEndpoint.handle); try app.listen(8080); } ``` -------------------------------- ### Authenticated Endpoint Example Source: https://github.com/zigzap/zap/blob/master/README.md Demonstrates how to create an authenticated endpoint in Zap. This example requires authentication before allowing access to the endpoint's functionality. ```zig const zap = @import("zap"); const AuthenticatedEndpoint = struct { const Self = @This(); pub fn handle(req: zap.http.Request, app_context: zap.App.Context) !void { // This code only runs if authentication is successful _ = req; _ = app_context; return zap.http.Response.new(200, "Access granted!"); } }; pub fn main() !void { // Assuming an authenticator is configured globally or per-endpoint var app = try zap.App.init(.{}); defer app.deinit(); // Add the authenticated endpoint. Authentication is handled by the app's configured authenticator. app.addEndpoint("/protected", AuthenticatedEndpoint.handle); try app.listen(8080); } ``` -------------------------------- ### HTTPS Server Setup in Zig Source: https://github.com/zigzap/zap/blob/master/README.md Shows how to configure and run an HTTPS server using Zap's OpenSSL support. Compilation requires `-Dopenssl=true` and OpenSSL development libraries. ```zig const std = @import("std"); const zap = @import("zap"); pub fn main() !void { // Ensure OpenSSL is enabled during compilation or via environment variable // Example compilation: zig build -Dopenssl=true run-https // Example runtime: ZAP_USE_OPENSSL=true ./your_app var app = try zap.Zap.init(); app.router.add("/", "GET", "/", fn(r: zap.Request) !zap.Response { return zap.Response.init(200, "Hello from HTTPS!"); }); // The listen function will automatically use HTTPS if OpenSSL is enabled // and certificate/key files are configured or found (e.g., cert.pem, key.pem) try app.listen(8443); } ``` -------------------------------- ### Zap Endpoint with PUT, DELETE, GET, POST Operations Source: https://github.com/zigzap/zap/blob/master/README.md A comprehensive example of a REST API using Zap's endpoint-based approach. It includes a `/users` endpoint supporting PUT, DELETE, GET, and POST operations, along with a simple frontend for interaction. ```zig // main.zig const zap = @import("zap"); const std = @import("std"); const UsersEndpoint = struct { const Self = @This(); pub fn handle_put(req: zap.http.Request, app_context: zap.App.Context) !void { // Handle PUT request _ = req; _ = app_context; return zap.http.Response.new(200, "User updated"); } pub fn handle_delete(req: zap.http.Request, app_context: zap.App.Context) !void { // Handle DELETE request _ = req; _ = app_context; return zap.http.Response.new(200, "User deleted"); } pub fn handle_get(req: zap.http.Request, app_context: zap.App.Context) !void { // Handle GET request _ = req; _ = app_context; return zap.http.Response.new(200, "User list"); } pub fn handle_post(req: zap.http.Request, app_context: zap.App.Context) !void { // Handle POST request _ = req; _ = app_context; return zap.http.Response.new(200, "User created"); } }; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{.retain_allocator_on_error = false}); defer _ = gpa.deinit(); const allocator = gpa.allocator(); var app = try zap.App.init(allocator, .{}); defer app.deinit(); app.addEndpoint("/users", UsersEndpoint.handle_put, zap.http.Method.PUT); app.addEndpoint("/users", UsersEndpoint.handle_delete, zap.http.Method.DELETE); app.addEndpoint("/users", UsersEndpoint.handle_get, zap.http.Method.GET); app.addEndpoint("/users", UsersEndpoint.handle_post, zap.http.Method.POST); try app.listen(8080); } ``` ```zig // stopendpoint.zig const zap = @import("zap"); const StopEndpoint = struct { const Self = @This(); pub fn handle(req: zap.http.Request, app_context: zap.App.Context) !void { _ = req; _ = app_context; zap.App.stop(); // Stops Zap return zap.http.Response.new(200, "Zap shutting down..."); } }; pub fn main() !void { var app = try zap.App.init(.{}); defer app.deinit(); app.addEndpoint("/stop", StopEndpoint.handle); try app.listen(8080); } ``` -------------------------------- ### Cookie Handling Example in Zig Source: https://github.com/zigzap/zap/blob/master/README.md Demonstrates sending a cookie to the client and then reading a session cookie back in subsequent requests. This is fundamental for session management. ```zig const std = @import("std"); const zap = @import("zap"); pub fn main() !void { var app = try zap.Zap.init(); app.router.add("/setcookie", "GET", "/setcookie", fn(r: zap.Request) !zap.Response { var response = try zap.Response.init(200, "Cookie set!"); response.setCookie("mycookie", "cookievalue", .{ .max_age = 3600 }); // Expires in 1 hour return response; }); app.router.add("/getcookie", "GET", "/getcookie", fn(r: zap.Request) !zap.Response { const cookie_value = r.cookies.get("mycookie"); if (cookie_value) |value| { return zap.Response.init(200, std.fmt.allocPrint(std.heap.page_allocator, "Cookie value: {s}\\n", .{value}) catch "Error formatting response"); } else { return zap.Response.init(400, "Cookie not found."); } }); try app.listen(8080); } ``` -------------------------------- ### Fetch User List Source: https://github.com/zigzap/zap/blob/master/examples/endpoint/html/index.html Fetches the list of users from the '/users' endpoint using a GET request. Logs the response and then calls showTable to display the data. ```javascript function getUserList() { fetch("/users", { method: "GET", } ) .then((response) => response.json()) .then((data) => { log("SUCESS: " + JSON.stringify(data)); showTable(data); }) .catch((error) => { log("Error fetching data"); }); } ``` -------------------------------- ### Receiving Binary Form Post Data in Zig Source: https://github.com/zigzap/zap/blob/master/README.md An example demonstrating how to receive binary files submitted via a form post. This is useful for handling file uploads. ```zig const std = @import("std"); const zap = @import("zap"); pub fn main() !void { var app = try zap.Zap.init(); app.router.add("/upload", "POST", "/upload", fn(r: zap.Request) !zap.Response { var form = try r.parseForm(); defer form.deinit(); // Assuming the file input field is named 'myFile' const file = form.getFile("myFile"); if (file) |f| { std.debug.print("Received file: {s}, size: {d}\\n", .{ f.filename, f.data.len }); // Process the file data (f.data) return zap.Response.init(200, "File uploaded successfully!"); } else { return zap.Response.init(400, "No file uploaded."); } }); try app.listen(8080); } ``` -------------------------------- ### Websockets Chat Example Source: https://github.com/zigzap/zap/blob/master/README.md A simple chat application implemented using WebSockets. This example showcases real-time, bi-directional communication between the server and multiple browser clients. ```zig // This example likely involves multiple files for client and server. // The server-side logic would use zap.Websocket. // Example server-side snippet (conceptual): const std = @import("std"); const zap = @import("zap"); pub fn main() !void { var app = try zap.Zap.init(); // Route for WebSocket upgrade requests app.router.add("/ws", "GET", "/ws", fn(r: zap.Request) !zap.Response { // Handle WebSocket upgrade and connection logic here // This would involve accepting the connection and managing message passing // using zap.Websocket or similar abstractions. return zap.Response.init(200, "WebSocket endpoint"); // Placeholder }); try app.listen(8080); } ``` -------------------------------- ### Add ZAP Dependency to build.zig Source: https://github.com/zigzap/zap/blob/master/tools/announceybot/release-note-template.md Integrate the ZAP dependency into your `build.zig` file before installing artifacts. Set `openssl` to `true` to enable TLS support. ```zig const zap = b.dependency("zap", .{ .target = target, .optimize = optimize, .openssl = false, // set to true to enable TLS support }); exe.root_module.addImport("zap", zap.module("zap")); ``` -------------------------------- ### Basic Routing in Zig Source: https://github.com/zigzap/zap/blob/master/README.md A straightforward example of dispatching requests based on the HTTP path using a simple, custom routing mechanism. For more realistic scenarios, consider using endpoint-based routing. ```zig const std = @import("std"); const zap = @import("zap"); pub fn main() !void { var app = try zap.Zap.init(); app.router.add("/", "GET", "/", "Hello World!"); app.router.add("/foo", "GET", "/foo", "Hello Foo!"); app.router.add("/bar", "GET", "/bar", "Hello Bar!"); try app.listen(8080); } ``` -------------------------------- ### Start and Stop Zap Server Source: https://context7.com/zigzap/zap/llms.txt Launches the IO reactor and blocks until `zap.stop` is called. Configure the number of worker threads and processes. The `on_request` handler is called for each incoming request. ```zig const std = @import("std"); const zap = @import("zap"); fn on_request(r: zap.Request) !void { try r.sendBody("

Hello from ZAP!

"); } pub fn main() !void { var listener = zap.HttpListener.init(.{ .port = 3000, .on_request = on_request, .log = true, }); try listener.listen(); std.debug.print("Listening on http://localhost:3000\n", .{}); zap.start(.{ .threads = 4, .workers = 1, // keep 1 when sharing mutable state }); // zap.stop() can be called from any request handler to unblock this } ``` -------------------------------- ### Fetch Zap Dependency Source: https://github.com/zigzap/zap/blob/master/README.md Fetches the Zap dependency using 'zig fetch' and saves it for use in a Zig project. Ensure you have Zig 0.15.1 or later installed. ```shell zig fetch --save "git+https://github.com/zigzap/zap#v0.11.0" ``` -------------------------------- ### Dynamic Hash Map Library Usage Source: https://github.com/zigzap/zap/blob/master/facil.io/LIBRARIES.md Illustrates using the fio_hash library for hash maps. Keys can be various data types, including strings. The example uses uint64_t keys and void* values. ```c // container on the stack (can also be placed on the heap). fio_hash_s hash = FIO_HASH_INIT; fio_hash_insert(&hash, 1, (void *)1); printf("Hash seek key %u => value: %zd", 1, fio_hash_find(&hash, 1)); printf("Hash seek key %u => value: %zd", 2, fio_hash_find(&hash, 2)); fio_hash_free(&ary); // use FIO_HASH_FOR_FREE to free object data or custom keys. ``` -------------------------------- ### Wrap Endpoint with Bearer Authentication Source: https://github.com/zigzap/zap/blob/master/doc/authentication.md This example demonstrates how to wrap a basic endpoint with Bearer token authentication using Zap's Endpoint.Authenticating. It sets up a listener, defines a custom endpoint, and configures a BearerSingle authenticator. ```zig const std = @import("std"); const zap = @import("zap"); const a = std.heap.page_allocator; const token = "ABCDEFG"; const HTTP_RESPONSE: []const u8 = \ \ Hello from ZAP!!! \ ; pub const Endpoint = struct { path: []const u8, // authenticated requests go here fn get(_: *Endpoint, r: zap.Request) void { r.sendBody(HTTP_RESPONSE) catch return; } // just for fun, we also catch the unauthorized callback fn unauthorized(_: *Endpoint, r: zap.Request) void { r.setStatus(.unauthorized); r.sendBody("UNAUTHORIZED ACCESS") catch return; } }; pub fn main() !void { // setup listener var listener = zap.EndpointListener.init( a, .{ .port = 3000, .on_request = null, .log = true, .max_clients = 10, .max_body_size = 1 * 1024, }, ); defer listener.deinit(); // create mini endpoint var ep : Endpoint = .{ .path = "/test", }; // create authenticator const Authenticator = zap.Auth.BearerSingle; var authenticator = try Authenticator.init(a, token, null); defer authenticator.deinit(); // create authenticating endpoint const BearerAuthEndpoint = zap.Endpoint.Authenticating(Endpoint, Authenticator); var auth_ep = BearerAuthEndpoint.init(&ep, &authenticator); try listener.register(&auth_ep); listener.listen() catch {}; std.debug.print( \ Run the following: \ \ curl http://localhost:3000/test -i -H "Authorization: Bearer ABCDEFG" -v \ curl http://localhost:3000/test -i -H "Authorization: Bearer invalid" -v \ \ and see what happens \ , .{} ); // start worker threads zap.start(.{ .threads = 1, .workers = 1, }); } ``` -------------------------------- ### Initialize Application Source: https://github.com/zigzap/zap/blob/master/examples/endpoint/html/index.html Initializes the application by fetching the user list when the page loads. ```javascript function init() { getUserList(); } init(); ``` -------------------------------- ### Configure zap.HttpListener for a Basic Server Source: https://context7.com/zigzap/zap/llms.txt Sets up a basic HTTP listener with request handling, static file serving, and configurable timeouts and body sizes. Ensure the 'public' folder exists for static file serving. ```zig const std = @import("std"); const zap = @import("zap"); fn on_request(r: zap.Request) !void { // Method dispatch example switch (r.methodAsEnum()) { .GET => try r.sendJson( \{"method":"GET","ok":true} ), .POST => { try r.parseBody(); if (r.body) |b| { std.debug.print("Body: {s} ", .{b}); } try r.sendJson( \{"method":"POST","received":true} ); }, else => { r.setStatus(.method_not_allowed); try r.sendBody("405"); }, } } pub fn main() !void { var listener = zap.HttpListener.init(.{ .port = 3000, .on_request = on_request, .public_folder = "./public", // serves static files from this dir .log = true, .max_clients = 100_000, .max_body_size = 50 * 1024 * 1024, .timeout = 5, }); try listener.listen(); zap.start(.{ .threads = 4, .workers = 1 }); } ``` -------------------------------- ### Serve Local API Docs with Zap Source: https://github.com/zigzap/zap/blob/master/README.md Run the Zap documentation server locally. You can specify a custom port and documentation directory. ```zig zig build run-docserver ``` ```zig zig build docserver && zig-out/bin/docserver --port=8989 --docs=path/to/docs ``` -------------------------------- ### UserPass Basic Authentication in Zap Source: https://github.com/zigzap/zap/blob/master/doc/authentication.md Configure UserPass Basic authentication with zap.Auth.Basic, providing a map of users to passwords. The map must support the `get` operation. ```zig const std = @import("std"); const zap = @import("zap"); const allocator = std.heap.page_allocator; // create a set of User -> Pass entries const Map = std.StringHashMap([]const u8); var map = Map.init(allocator); defer map.deinit(); // create user / pass entry const user = "Alladdin"; const pass = "opensesame"; try map.put(user, pass); // create authenticator const Authenticator = zap.Auth.Basic(Map, .UserPass); var auth = try Authenticator.init(a, &map, null); defer auth.deinit(); fn on_request(r: zap.Request) void { if(authenticator.authenticateRequest(r)) { r.sendBody( \ \

Hello from ZAP!!!

\ ) catch return; } else { r.setStatus(.unauthorized); r.sendBody("UNAUTHORIZED") catch return; } } ``` -------------------------------- ### Configure zap.Router for Path Dispatch Source: https://context7.com/zigzap/zap/llms.txt Illustrates setting up a zap.Router to dispatch requests based on exact path matches. It shows how to bind both unbound functions and bound struct methods to specific routes, and how to define a custom handler for 404 Not Found errors. ```zig const std = @import("std"); const zap = @import("zap"); const Api = struct { count: u32 = 0, pub fn getCount(self: *Api, r: zap.Request) !void { var buf: [64]u8 = undefined; const s = try std.fmt.bufPrint(&buf, "count={d}", .{self.count}); try r.sendBody(s); } pub fn increment(self: *Api, r: zap.Request) !void { self.count += 1; try r.sendBody("incremented"); } }; fn not_found(r: zap.Request) !void { r.setStatus(.not_found); try r.sendBody("404 Not Found"); } pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){}; const alloc = gpa.allocator(); var api = Api{}; var router = zap.Router.init(alloc, .{ .not_found = not_found }); defer router.deinit(); // Bind free function to "/" try router.handle_func_unbound("/", struct { fn h(r: zap.Request) !void { try r.sendBody("Welcome"); } }.h); // Bind struct methods try router.handle_func("/count", &api, &Api.getCount); try router.handle_func("/increment", &api, &Api.increment); var listener = zap.HttpListener.init(.{ .port = 3000, .on_request = router.on_request_handler(), .log = true, }); try listener.listen(); zap.start(.{ .threads = 2, .workers = 1 }); // curl http://localhost:3000/count // curl http://localhost:3000/increment } ``` -------------------------------- ### Integrate Zap into build.zig Source: https://context7.com/zigzap/zap/llms.txt Configure your `build.zig` file to include Zap as a dependency for your executable. Set `openssl` to `true` to enable TLS/HTTPS support. ```zig const zap = b.dependency("zap", .{ .target = target, .optimize = optimize, .openssl = false, // set true to enable TLS/HTTPS }); exe.root_module.addImport("zap", zap.module("zap")); ``` -------------------------------- ### Import ZAP Module in build.zig Source: https://github.com/zigzap/zap/blob/master/doc/release-template.md Add this code to your build.zig file's `build` function to make the ZAP module available in your project. Set the `openssl` option to `true` if TLS support is required. ```zig const zap = b.dependency("zap", .{ .target = target, .optimize = optimize, .openssl = false, // set to true to enable TLS support }); exe.root_module.addImport("zap", zap.module("zap")); ``` -------------------------------- ### zap.Request - Handling HTTP Requests Source: https://context7.com/zigzap/zap/llms.txt Demonstrates how to inspect incoming request fields like path, query, body, and method. It also shows how to parse request bodies and queries, retrieve parameters and headers, and send various types of responses. ```APIDOC ## zap.Request — HTTP Request Object `zap.Request` is the central type passed to every handler. It provides access to path, query, body, method, headers, parameters, cookies, and response-sending functions. Parse body/query before reading parameters. ```zig fn on_request(r: zap.Request) !void { // --- Inspect incoming fields --- if (r.path) |p| std.debug.print("PATH: {s}\\n", .{p}); if (r.query) |q| std.debug.print("QUERY: {s}\\n", .{q}); if (r.body) |b| std.debug.print("BODY: {s}\\n", .{b}); if (r.method) |m| std.debug.print("METHOD: {s}\\n", .{m}); // --- Parse & read parameters --- try r.parseBody(); // must call before reading body params r.parseQuery(); // must call before reading query params var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const alloc = arena.allocator(); if (try r.getParamStr(alloc, "username")) |username| { defer alloc.free(username); std.debug.print("username={s}\\n", .{username}); } // Zero-alloc query param slice (no decode, no parse needed) if (r.getParamSlice("token")) |token| { std.debug.print("token={s}\\n", .{token}); } // --- Read a request header --- if (r.getHeader("content-type")) |ct| { std.debug.print("Content-Type: {s}\\n", .{ct}); } if (r.getHeaderCommon(.accept)) |accept| { std.debug.print("Accept: {s}\\n", .{accept}); } // --- Send responses --- r.setStatus(.ok); try r.setHeader("X-Powered-By", "zap"); try r.sendJson( \{"status":"ok","message":"hello"} ); // sets Content-Type: application/json automatically // Alternative: send raw body // try r.sendBody("

Hello

"); // Redirect // try r.redirectTo("/new-path", .found); // Send a file with gzip + range support // try r.sendFile("./public/index.html"); // Send error with stack trace (useful in debug mode) // r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 500); } ``` ``` -------------------------------- ### Dynamic String Library Usage Source: https://github.com/zigzap/zap/blob/master/facil.io/LIBRARIES.md Demonstrates creating and manipulating dynamic strings using the fio_str library. Supports both stack and heap allocated containers. Short strings are optimized for performance. ```c // container on the stack fio_str_s str = FIO_STR_INIT; fio_str_write(&str, "Hello", 5); fio_str_printf(&str, " world, %d", 42); printf("%s\n", fio_str_data(&str)); // "Hello world, 42" fio_str_free(&str); // container on the heap fio_str_s *str = malloc(sozeof(*str)); *str = FIO_STR_INIT; // use ... and ... free when done: fio_str_free(str); free(str); ``` -------------------------------- ### Fetch New Release with Zig Source: https://github.com/zigzap/zap/blob/master/tools/announceybot/release-announcement-template.md Use this command to fetch and save a specific release of the zigzap/zap project. Replace `{tag}` with the desired release tag. ```bash zig fetch --save "git+https://github.com/zigzap/zap#{tag}" ``` -------------------------------- ### Simple Router with zap.Router in Zig Source: https://github.com/zigzap/zap/blob/master/README.md Demonstrates the use of `zap.Router` for dispatching HTTP requests to specific handlers based on their path. This provides a more structured approach to routing than manual path checking. ```zig const std = @import("std"); const zap = @import("zap"); fn handleRoot(r: zap.Request) !zap.Response { return zap.Response.init(200, "Root Handler"); } fn handleFoo(r: zap.Request) !zap.Response { return zap.Response.init(200, "Foo Handler"); } pub fn main() !void { var app = try zap.Zap.init(); app.router.add("/", "GET", "/", handleRoot); app.router.add("/foo", "GET", "/foo", handleFoo); try app.listen(8080); } ``` -------------------------------- ### Register Custom MIME Types with zap.mimetypeRegister Source: https://context7.com/zigzap/zap/llms.txt Registers custom file extensions to MIME type mappings before starting the HTTP listener. This is useful for serving non-standard file types. Use zap.mimetypeClear() to remove all registered types. ```zig const zap = @import("zap"); pub fn main() !void { // Register custom MIME types before starting the listener zap.mimetypeRegister("wasm", "application/wasm"); zap.mimetypeRegister("avif", "image/avif"); zap.mimetypeRegister("webp", "image/webp"); // Clear all registered MIME types (including built-ins) // zap.mimetypeClear(); var listener = zap.HttpListener.init(.{ .port = 3000, .on_request = null, .public_folder = "./public", .log = true, }); try listener.listen(); zap.start(.{ .threads = 2, .workers = 1 }); } ``` -------------------------------- ### Zap HTTPS/TLS Support Source: https://context7.com/zigzap/zap/llms.txt Enable HTTPS by wrapping facil.io's OpenSSL integration with zap.Tls. Build with -Dopenssl=true and pass a Tls instance to HttpListenerSettings.tls. ```zig const std = @import("std"); const zap = @import("zap"); // Generate certs: // openssl req -x509 -nodes -days 365 -sha256 -newkey rsa:2048 \ // -keyout mykey.pem -out mycert.pem pub fn main() !void { const tls = try zap.Tls.init(.{ .server_name = "localhost:4443", .public_certificate_file = "mycert.pem", .private_key_file = "mykey.pem", // .private_key_password = null, // omit if PEM is not password-protected }); defer tls.deinit(); var listener = zap.HttpListener.init(.{ .port = 4443, .on_request = struct { fn h(r: zap.Request) !void { try r.sendBody("Secure!"); } }.h, .tls = tls, .log = true, }); try listener.listen(); std.debug.print("HTTPS on https://localhost:4443\n", .{}); zap.start(.{ .threads = 2, .workers = 1 }); // curl -k https://localhost:4443/ } // Build: zig build -Dopenssl=true run-https ``` -------------------------------- ### Inspect zap.Request Fields and Send Response Source: https://context7.com/zigzap/zap/llms.txt Demonstrates how to access path, query, body, and method from a zap.Request. It also shows how to parse parameters, read headers, and send JSON or raw body responses. Ensure body/query are parsed before reading parameters. ```zig fn on_request(r: zap.Request) !void { // --- Inspect incoming fields --- if (r.path) |p| std.debug.print("PATH: {s} ", .{p}); if (r.query) |q| std.debug.print("QUERY: {s} ", .{q}); if (r.body) |b| std.debug.print("BODY: {s} ", .{b}); if (r.method) |m| std.debug.print("METHOD: {s} ", .{m}); // --- Parse & read parameters --- try r.parseBody(); // must call before reading body params r.parseQuery(); // must call before reading query params var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const alloc = arena.allocator(); if (try r.getParamStr(alloc, "username")) |username| { defer alloc.free(username); std.debug.print("username={s} ", .{username}); } // Zero-alloc query param slice (no decode, no parse needed) if (r.getParamSlice("token")) |token| { std.debug.print("token={s} ", .{token}); } // --- Read a request header --- if (r.getHeader("content-type")) |ct| { std.debug.print("Content-Type: {s} ", .{ct}); } if (r.getHeaderCommon(.accept)) |accept| { std.debug.print("Accept: {s} ", .{accept}); } // --- Send responses --- r.setStatus(.ok); try r.setHeader("X-Powered-By", "zap"); try r.sendJson( \{"status":"ok","message":"hello"} ); // sets Content-Type: application/json automatically // Alternative: send raw body // try r.sendBody("

Hello

"); // Redirect // try r.redirectTo("/new-path", .found); // Send a file with gzip + range support // try r.sendFile("./public/index.html"); // Send error with stack trace (useful in debug mode) // r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 500); } ``` -------------------------------- ### Add ZAP Dependency to build.zig.zon Source: https://github.com/zigzap/zap/blob/master/doc/release-template.md Include this snippet in your build.zig.zon file to declare ZAP as a dependency. Replace `{tag}` and `{hash}` with the appropriate values for the ZAP version you are using. ```zig // zap {tag} .zap = .{ .url = "https://github.com/zigzap/zap/archive/refs/tags/{tag}.tar.gz", .hash = "{hash}", } ``` -------------------------------- ### Static File Server with Dynamic Handling in Zig Source: https://github.com/zigzap/zap/blob/master/README.md Implements a traditional static web server that can optionally handle dynamic requests. This allows serving static assets while also processing specific API endpoints. ```zig const std = @import("std"); const zap = @import("zap"); fn handleDynamic(r: zap.Request) !zap.Response { return zap.Response.init(200, "Dynamic Request Handled!"); } pub fn main() !void { var app = try zap.Zap.init(); // Serve static files from the 'static' directory app.serve("static"); // Add a dynamic route app.router.add("/api/data", "GET", "/api/data", handleDynamic); try app.listen(8080); } ``` -------------------------------- ### Zap Middleware Chain with Strongly-Typed Context Source: https://context7.com/zigzap/zap/llms.txt Implement a Go-style middleware pipeline with a per-request context. Each handler passes control to the next using handler.handleOther(). Requires a default value for context fields. ```zig const std = @import("std"); const zap = @import("zap"); // Shared per-request context; fields must have default values const Ctx = struct { user_id: ?u64 = null, auth_token: ?[]const u8 = null, }; const Handler = zap.Middleware.Handler(Ctx); // Auth middleware: validates a bearer token and populates context const AuthMiddleware = struct { handler: Handler, pub fn init(next: ?*Handler) AuthMiddleware { return .{ .handler = Handler.init(onRequest, next) }; } pub fn getHandler(self: *AuthMiddleware) *Handler { return &self.handler; } pub fn onRequest(h: *Handler, r: zap.Request, ctx: *Ctx) !bool { const self: *AuthMiddleware = @fieldParentPtr("handler", h); _ = self; if (r.getHeader("authorization")) |hdr| { if (std.mem.startsWith(u8, hdr, "Bearer ")) { ctx.auth_token = hdr[7..]; ctx.user_id = 42; // would normally do a DB lookup } } return h.handleOther(r, ctx); // continue chain } }; // Final handler: uses the populated context to respond const ResponseMiddleware = struct { handler: Handler, pub fn init(next: ?*Handler) ResponseMiddleware { return .{ .handler = Handler.init(onRequest, next) }; } pub fn getHandler(self: *ResponseMiddleware) *Handler { return &self.handler; } pub fn onRequest(_: *Handler, r: zap.Request, ctx: *Ctx) !bool { var buf: [256]u8 = undefined; const msg = if (ctx.user_id) |uid| try std.fmt.bufPrint(&buf, "Hello user {d}", .{uid}) else try std.fmt.bufPrint(&buf, "Hello anonymous", .{}); try r.sendBody(msg); return true; // stop chain } }; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){}; const alloc = gpa.allocator(); var resp_handler = ResponseMiddleware.init(null); var auth_handler = AuthMiddleware.init(resp_handler.getHandler()); var listener = try zap.Middleware.Listener(Ctx).init( .{ .on_request = null, .port = 3000, .log = true }, auth_handler.getHandler(), struct { fn get() std.mem.Allocator { return std.heap.page_allocator; } }.get, ); try listener.listen(); zap.start(.{ .threads = 2, .workers = 1 }); // curl http://localhost:3000/ -H "Authorization: Bearer token123" } ``` -------------------------------- ### Create Zap App with Global Context Source: https://context7.com/zigzap/zap/llms.txt Use zap.App.Create to parameterize an App type with a global context struct. Handlers receive a per-thread arena allocator and a pointer to the global context. Errors are governed by the endpoint's error_strategy. ```zig const std = @import("std"); const zap = @import("zap"); // Global application context shared across all endpoints const AppCtx = struct { db_url: []const u8, }; // A REST endpoint for /api/items const ItemsEndpoint = struct { path: []const u8, error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response, pub fn get(self: *ItemsEndpoint, arena: std.mem.Allocator, ctx: *AppCtx, r: zap.Request) !void { _ = self; const body = try std.fmt.allocPrint(arena, \\{{"db":"{s}","items":["a","b","c"]}} , .{@ ctx.db_url}); try r.sendJson(body); // sets Content-Type: application/json } pub fn post(_: *ItemsEndpoint, arena: std.mem.Allocator, _: *AppCtx, r: zap.Request) !void { try r.parseBody(); if (try r.getParamStr(arena, "name")) |name| { defer arena.free(name); const resp = try std.fmt.allocPrint(arena, "Created: {s}", .{@ name}); r.setStatus(.created); try r.sendBody(resp); } else { r.setStatus(.bad_request); try r.sendBody("missing 'name' param"); } } }; // A /stop endpoint for clean shutdown const StopEndpoint = struct { path: []const u8, error_strategy: zap.Endpoint.ErrorStrategy = .log_to_console, pub fn get(_: *StopEndpoint, _: std.mem.Allocator, _: *AppCtx, _: zap.Request) !void { zap.stop(); } }; pub fn main() !void { var gpa: std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }) = .{}; defer _ = gpa.deinit(); const alloc = gpa.allocator(); var ctx = AppCtx{ .db_url = "postgres://localhost/mydb" }; const App = zap.App.Create(AppCtx); try App.init(alloc, &ctx, .{}); defer App.deinit(); var items_ep = ItemsEndpoint{ .path = "/api/items" }; var stop_ep = StopEndpoint{ .path = "/stop" }; try App.register(&items_ep); try App.register(&stop_ep); try App.listen(.{ .interface = "0.0.0.0", .port = 3000 }); std.debug.print("Listening on :3000\n", .{}); zap.start(.{ .threads = 2, .workers = 1 }); // curl http://localhost:3000/api/items // curl -X POST http://localhost:3000/api/items -d "name=widget" } ``` -------------------------------- ### Dynamic Array Library Usage Source: https://github.com/zigzap/zap/blob/master/facil.io/LIBRARIES.md Shows how to use the fio_ary library for dynamic arrays. Arrays can be allocated on the stack or heap. ```c // container on the stack (can also be placed on the heap). fio_ary_s ary = FIO_ARY_INIT; fio_ary_push(&ary, (void *)1); printf("Array pop value: %zd", (size_t)fio_ary_pop(&ary)); fio_ary_free(&ary); ```