Dg0230/h3z
H3z is a modern HTTP framework for Zig, offering a high-performance, easy-to-use interface for building web servers and APIs. It leverages Zig's memor...
main.tar.gz
⚡️ A minimal, fast, and composable HTTP server framework for Zig, inspired by H3.js.
Add H3 to your build.zig.zon
:
.dependencies = .{
.h3 = .{
.url = "https://github.com/dg0230/h3z/archive/main.tar.gz",
.hash = "...",
},
},
const std = @import("std");
const h3 = @import("h3");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Create H3 app
var app = h3.createApp(allocator);
defer app.deinit();
// Add routes
_ = app.get("/", helloHandler);
_ = app.get("/api/users/:id", getUserHandler);
_ = app.post("/api/users", createUserHandler);
// Start server
try h3.serve(&app, .{ .port = 3000 });
}
fn helloHandler(event: *h3.Event) !void {
try h3.sendText(event, "⚡️ Hello from H3!");
}
fn getUserHandler(event: *h3.Event) !void {
const user_id = h3.getParam(event, "id") orelse {
try h3.utils.response.badRequest(event, "Missing user ID");
return;
};
const user = .{ .id = user_id, .name = "John Doe" };
try h3.sendJson(event, user);
}
fn createUserHandler(event: *h3.Event) !void {
const User = struct { name: []const u8 };
const user_data = try h3.readJson(event, User);
event.setStatus(.created);
try h3.sendJson(event, .{ .id = 123, .name = user_data.name });
}
// Create app
var app = h3.createApp(allocator);
defer app.deinit();
// HTTP methods
_ = app.get("/path", handler);
_ = app.post("/path", handler);
_ = app.put("/path", handler);
_ = app.delete("/path", handler);
_ = app.patch("/path", handler);
_ = app.head("/path", handler);
_ = app.options("/path", handler);
_ = app.all("/path", handler); // All methods
// Middleware
_ = app.use(middleware);
The H3Event
is the central context object that carries request and response data:
fn handler(event: *h3.Event) !void {
// Request info
const method = event.getMethod();
const path = event.getPath();
const url = event.getUrl();
// Headers
const auth = event.getHeader("authorization");
try event.setHeader("x-custom", "value");
// Parameters and query
const id = h3.getParam(event, "id");
const page = h3.getQuery(event, "page");
// Body
const body = h3.readBody(event);
const json_data = try h3.readJson(event, MyStruct);
// Response
event.setStatus(.ok);
try h3.sendText(event, "Hello");
try h3.sendJson(event, "{\"message\": \"Hello\"}");
try h3.sendJson(event, .{ .message = "Hello" });
try h3.response.redirect(event, "/new-path", .moved_permanently);
}
// Response helpers
try h3.sendText(event, "text");
try h3.sendJson(event, json_string);
try h3.sendJson(event, struct_or_value);
try h3.utils.response.redirect(event, "/path", .found);
// Error responses
try h3.utils.response.notFound(event, "Custom message");
try h3.utils.response.badRequest(event, "Invalid input");
try h3.utils.response.unauthorized(event, null);
try h3.utils.response.forbidden(event, null);
try h3.utils.response.internalServerError(event, null);
// Request helpers
const header = event.getHeader("content-type");
const param = h3.getParam(event, "id");
const query = h3.getQuery(event, "page");
const body = h3.readBody(event);
const json = try h3.readJson(event, MyStruct);
// Security and CORS
try h3.utils.response.setCors(event, "*");
try h3.utils.response.setSecurity(event);
try h3.utils.response.setNoCache(event);
fn loggerMiddleware(event: *h3.Event, context: h3.MiddlewareContext, index: usize, final_handler: h3.Handler) !void {
std.log.info("{s} {s}", .{ event.getMethod().toString(), event.getPath() });
try context.next(event, index, final_handler);
}
fn corsMiddleware(event: *h3.Event, context: h3.MiddlewareContext, index: usize, final_handler: h3.Handler) !void {
try h3.utils.response.setCors(event, "*");
if (event.getMethod() == .OPTIONS) {
event.setStatus(.no_content);
return;
}
try context.next(event, index, final_handler);
}
// Built-in middleware
_ = app.use(h3.middleware.logger);
_ = app.use(h3.middleware.cors("*"));
_ = app.use(h3.middleware.security);
// Start server with options
try h3.serve(&app, .{
.port = 3000,
.host = "127.0.0.1",
.backlog = 128,
});
// Start with defaults (port 3000)
try h3.serve(&app, .{});
H3 supports simple route patterns:
/api/users
/api/users/:id
(accessible via event.getParam("id")
)/static/*
(matches any path starting with /static/
)# Build the project
zig build
# Run tests
zig build test
# Run the example
zig build run
# Build in release mode
zig build -Doptimize=ReleaseFast
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit issues and pull requests.
Advanced routing (regex patterns, route groups)
WebSocket support
Static file serving
Template engine integration
Database integration helpers
Session management
Rate limiting
Compression middleware
File upload handling
Testing utilities
This project is inspired by H3.js, bringing similar concepts and ergonomics to the Zig ecosystem while leveraging Zig's unique strengths in performance and safety.