Middleware Reference
Overview
Zigmund middleware intercepts requests and responses in the processing pipeline. Middleware can be added via app.addMiddleware and runs in registration order for requests and reverse order for responses.
Middleware Type
pub const Middleware = struct {
name: []const u8,
context: ?*anyopaque = null,
request_hook: ?RequestMiddlewareFn = null,
response_hook: ?ResponseMiddlewareFn = null,
request_hook_with_context: ?RequestMiddlewareWithContextFn = null,
response_hook_with_context: ?ResponseMiddlewareWithContextFn = null,
deinit_hook: ?MiddlewareDeinitFn = null,
};
Built-in Middleware
CORS -- corsMw
try app.addMiddleware(zigmund.corsMw(zigmund.CorsOptions{
.allowed_origins = &.{ "https://example.com" },
.allowed_methods = &.{ "GET", "POST" },
.allow_credentials = true,
}));
CorsOptions:
| Field | Type | Default | Description |
|---|---|---|---|
allowed_origins |
[]const []const u8 |
&.{"*"} |
Allowed origin domains |
allowed_methods |
[]const []const u8 |
&.{"GET","POST","PUT","PATCH","DELETE","OPTIONS","HEAD"} |
Allowed HTTP methods |
allowed_headers |
[]const []const u8 |
&.{"Content-Type","Authorization","Accept","Origin","X-Requested-With"} |
Allowed request headers |
expose_headers |
[]const []const u8 |
&.{} |
Headers exposed to the browser |
allow_credentials |
bool |
false |
Allow credentials (cookies, auth) |
max_age |
u32 |
86400 |
Preflight cache duration in seconds |
Rate Limiting -- rateLimitMw
try app.addMiddleware(zigmund.rateLimitMw(zigmund.RateLimitOptions{
.max_requests = 100,
.window_seconds = 60,
}));
RateLimitOptions:
| Field | Type | Default | Description |
|---|---|---|---|
max_requests |
u32 |
100 |
Maximum requests per window |
window_seconds |
u32 |
60 |
Window duration in seconds |
key_func |
?*const fn (*Request) []const u8 |
null |
Custom client key extraction function |
CSRF Protection -- csrfMw
try app.addMiddleware(zigmund.csrfMw(zigmund.CsrfOptions{}));
CsrfOptions:
| Field | Type | Default | Description |
|---|---|---|---|
cookie_name |
[]const u8 |
"_csrf_token" |
CSRF cookie name |
header_name |
[]const u8 |
"X-CSRF-Token" |
Header to check for the token |
field_name |
[]const u8 |
"csrf_token" |
Form field name for the token |
token_bytes |
u8 |
32 |
Token length in bytes (hex output is 2x) |
safe_methods |
[]const std.http.Method |
&.{.GET,.HEAD,.OPTIONS,.TRACE} |
Methods exempt from validation |
cookie_path |
[]const u8 |
"/" |
Cookie path |
cookie_secure |
bool |
false |
Cookie secure flag |
cookie_same_site |
enum{strict,lax,none} |
.lax |
Cookie SameSite attribute |
Response Compression -- compressionMw
try app.addMiddleware(zigmund.compressionMw(zigmund.CompressionOptions{}));
CompressionOptions:
| Field | Type | Default | Description |
|---|---|---|---|
min_size |
usize |
1024 |
Minimum body size to trigger compression |
compressible_types |
[]const []const u8 |
(text, JSON, XML, JS, SVG) | Content types eligible for compression |
level |
u4 |
6 |
Compression level (1-9) |
Session Management -- sessionMw / sessionMwWithStore
try app.addMiddleware(zigmund.sessionMw(zigmund.SessionOptions{}));
// Or with a custom store:
var store = zigmund.InMemoryStore.init(allocator);
try app.addMiddleware(zigmund.sessionMwWithStore(zigmund.SessionOptions{}, store.asSessionStore()));
SessionOptions:
| Field | Type | Default | Description |
|---|---|---|---|
cookie_name |
[]const u8 |
"session_id" |
Session cookie name |
max_age |
u32 |
3600 |
Session expiry in seconds |
cookie_path |
[]const u8 |
"/" |
Cookie path |
http_only |
bool |
true |
HttpOnly flag |
secure |
bool |
false |
Secure flag |
same_site |
enum{strict,lax,none} |
.lax |
SameSite attribute |
SessionStore interface:
pub const SessionStore = struct {
ptr: *anyopaque,
getFn: *const fn (*anyopaque, []const u8) ?*SessionData,
putFn: *const fn (*anyopaque, []const u8) anyerror!*SessionData,
removeFn: *const fn (*anyopaque, []const u8) void,
};
InMemoryStore is the default in-memory implementation of SessionStore.
Request Timeout -- timeoutMw
try app.addMiddleware(zigmund.timeoutMw(zigmund.TimeoutConfig{
.timeout_ms = 30000,
.message = "Request timeout",
}));
TimeoutConfig:
| Field | Type | Default | Description |
|---|---|---|---|
timeout_ms |
u64 |
30000 |
Maximum processing time in milliseconds |
message |
[]const u8 |
"Request timeout" |
Response body on timeout |
HTTPS Redirect -- httpsRedirectMw
try app.addMiddleware(zigmund.httpsRedirectMw(zigmund.HttpsRedirectConfig{}));
HttpsRedirectConfig:
| Field | Type | Default | Description |
|---|---|---|---|
redirect_status |
std.http.Status |
.temporary_redirect |
Redirect status code |
https_port |
?u16 |
null |
Target HTTPS port (null uses 443) |
Content Negotiation -- contentNegotiationMw
try app.addMiddleware(zigmund.contentNegotiationMw(zigmund.ContentNegotiationConfig{
.default = .json,
.supported = &.{ .json, .plain_text, .html },
}));
ContentNegotiationConfig:
| Field | Type | Default | Description |
|---|---|---|---|
default |
ContentType |
.json |
Default content type |
supported |
[]const ContentType |
&.{.json,.plain_text,.html} |
Supported content types |
ContentType values: .json, .plain_text, .html, .xml, .any
Trusted Host -- trustedHostMw
try app.addMiddleware(zigmund.trustedHostMw(zigmund.TrustedHostConfig{
.allowed_hosts = &.{ "api.example.com", ".example.com" },
}));
TrustedHostConfig:
| Field | Type | Default | Description |
|---|---|---|---|
allowed_hosts |
[]const []const u8 |
&.{"*"} |
Allowed host values (supports wildcard subdomains with . prefix) |
allow_missing_host |
bool |
false |
Allow requests without a Host header |
Example
var app = try zigmund.App.init(allocator, .{ .title = "API", .version = "1.0" });
try app.addMiddleware(zigmund.corsMw(.{ .allowed_origins = &.{"*"} }));
try app.addMiddleware(zigmund.rateLimitMw(.{ .max_requests = 200 }));
try app.addMiddleware(zigmund.compressionMw(.{}));
try app.addMiddleware(zigmund.timeoutMw(.{ .timeout_ms = 15000 }));