Forms and Files
Zigmund supports receiving both form fields and file uploads in a single multipart/form-data request. Declare a zigmund.Form() parameter for the form fields and a zigmund.File() parameter for the uploaded file.
Overview
Some endpoints need both structured form data (text fields, checkboxes) and file uploads in the same request. For example, a profile update might include a username (text field) and an avatar image (file). Zigmund handles this by combining Form() and File() parameters in the same handler.
Example
const std = @import("std");
const zigmund = @import("zigmund");
const ProfileForm = struct {
username: []const u8,
bio: []const u8,
};
fn updateProfile(
form: zigmund.Form(ProfileForm, .{
.media_type = "multipart/form-data",
.description = "Profile metadata",
}),
avatar: zigmund.File(zigmund.UploadFile, .{
.description = "Profile avatar image",
}),
allocator: std.mem.Allocator,
) !zigmund.Response {
const data = form.value.?;
const file = avatar.value.?;
return zigmund.Response.json(allocator, .{
.username = data.username,
.bio = data.bio,
.avatar_filename = file.filename,
.avatar_content_type = file.content_type,
.avatar_bytes = file.data.len,
});
}
Register the route:
try app.post("/profile", updateProfile, .{});
How It Works
- Form parameter.
zigmund.Form(ProfileForm, .{ .media_type = "multipart/form-data" })parses the text fields from the multipart body. Setting.media_typeto"multipart/form-data"tells Zigmund (and the OpenAPI spec) that this form is part of a multipart request, not a URL-encoded one. - File parameter.
zigmund.File(zigmund.UploadFile, .{ .description = "Profile avatar image" })extracts the file part from the same multipart body. - Single request. Both parameters are populated from the same
multipart/form-datarequest body. Zigmund separates text parts from file parts automatically. - Access the data.
form.value.?gives you the struct with text fields.avatar.value.?gives you theUploadFilewith filename, content type, and raw bytes.
Key Points
- Media type matters. When combining forms and files, set
.media_type = "multipart/form-data"on theForm()parameter. Without this, the form defaults toapplication/x-www-form-urlencoded, which cannot carry file data. - Descriptions for OpenAPI. The
.descriptionoption on bothForm()andFile()adds documentation to the OpenAPI schema, making the Swagger UI more informative. - Multiple files. You can declare multiple
zigmund.File()parameters to accept several files in one request. Each file parameter corresponds to a different form field name. - Optional files. If the file is not required, check
avatar.valuefornullbefore unwrapping. - Field name matching. The parameter name in the handler signature (e.g.,
avatar) determines which multipart field name Zigmund looks for. The client must send the file under a matching field name.
See Also
- Request Forms -- Handling form data without file uploads.
- Request Files -- Handling file uploads without additional form fields.
- Request Form Models -- Structured form models with validation.