### 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);
```