Multiple Body Parameters
Zigmund lets you combine path parameters, query parameters, and a JSON body in a single handler. Each parameter source is declared with its own marker type, and Zigmund resolves them all automatically.
Overview
Real-world endpoints often need data from multiple sources: an item ID from the URL path, an optional filter from the query string, and the update payload from the request body. Zigmund's parameter markers -- Path(), Query(), and Body() -- can coexist in the same handler signature, each extracting its value from the appropriate part of the request.
Example
const std = @import("std");
const zigmund = @import("zigmund");
const ItemData = struct {
name: []const u8,
price: f64,
is_offer: bool = false,
};
fn updateItem(
item_id: zigmund.Path(u32, .{ .alias = "item_id" }),
q: zigmund.Query([]const u8, .{ .alias = "q", .required = false }),
item: zigmund.Body(ItemData, .{}),
allocator: std.mem.Allocator,
) !zigmund.Response {
const body = item.value.?;
return zigmund.Response.json(allocator, .{
.item_id = item_id.value.?,
.q = q.value,
.name = body.name,
.price = body.price,
.is_offer = body.is_offer,
});
}
Register the route:
try app.put("/items/{item_id}", updateItem, .{});
How It Works
- Path parameter.
zigmund.Path(u32, .{ .alias = "item_id" })extracts the{item_id}segment from the URL and parses it as au32. - Query parameter.
zigmund.Query([]const u8, .{ .alias = "q", .required = false })reads the?q=...query string parameter. Because.required = false, the handler still works whenqis omitted. - Body parameter.
zigmund.Body(ItemData, .{})parses the JSON request body into anItemDatastruct. - All resolved together. Zigmund resolves all three before calling the handler. If any required parameter is missing or invalid, an error response is returned automatically.
A request like PUT /items/42?q=search with body {"name":"Gadget","price":9.99} would populate all three parameters.
Key Points
- Parameter source is explicit.
Path(),Query(), andBody()each declare exactly where the value comes from. There is no ambiguity. - Default values. The
ItemDatastruct usesis_offer: bool = falseas a default. If the JSON body omitsis_offer, it defaults tofalse. - Optional query params. Setting
.required = falsemakes the query parameter optional. Theq.valuewill benullif not provided. - Single body only. A handler can have at most one
Body()parameter. If you need multiple JSON objects, nest them inside a single struct. - Order does not matter. Parameters can appear in any order in the handler signature. Zigmund resolves them by type, not position (except for
std.mem.Allocator, which is always provided).
See Also
- Body Fields -- Adding validation constraints to body fields.
- Nested Models -- Using nested structs for complex JSON payloads.
- Path Parameters -- Working with path parameters in detail.
- Query Parameters -- Working with query parameters in detail.