Forms, Cookies, and Static Files
This page covers the practical helpers that sit beside routing: decoded request bodies, cookies, signed cookies, and file serving.
URL-Encoded Forms
Use form_values for application/x-www-form-urlencoded request bodies and
query_values for decoded query strings. Both return FormValues, which
preserves insertion order and duplicate field names.
case form_values req {
Ok values -> case form_get "name" values {
Just name -> text 200 $"hello {name}"
Nothing -> text 400 "missing name"
}
Err _ -> text 400 "bad form"
}Use form_get_all for repeated names like checkbox groups or tags. Parser
limits come from RequestParserConfig; create_app installs defaults, and
use_options changes them app-wide.
Multipart Forms
Use multipart_values for buffered multipart/form-data. It returns
MultipartFormValues, whose entries are either MultipartText String or
MultipartFileValue MultipartFile.
case multipart_values req {
Ok values -> case multipart_file "upload" values {
Just file -> text 200 $"received {file.filename}"
Nothing -> text 400 "missing file"
}
Err _ -> text 400 "bad multipart body"
}Buffered multipart parsing keeps each text value and file body in memory. Size
limits are enabled by default; use use_options or multipart_values_with to
tune them. For saving client filenames, call sanitize_filename before
treating a filename as a local basename.
For large uploads, streaming handlers can parse multipart bodies incrementally:
stream_multipart req [] on_text on_fileUse stream_multipart_to_temp_files when the app wants Edda to write uploaded
files to caller-owned temp paths and return metadata. Call
delete_multipart_temp_files after the app is done with those files.
Cookies
cookies req parses all Cookie headers into ordered (name, value) pairs.
cookie "session" req returns the first matching value.
Response helpers append Set-Cookie headers:
text 200 "ok"
|> set_cookie "theme" "dark"
|> set_cookie_with "session" "abc" default_session_cookie_optionsUse delete_cookie to expire a cookie. The checked variants validate cookie
names and return Result Response CookieError.
Signed Cookies
Edda.Crypto signs cookie values with HMAC. Signed cookies are tamper-evident,
not encrypted.
let secret = cookie_secret "dev-only-secret"
case signed_cookie secret "session" req {
Ok user -> text 200 $"welcome {user}"
Err _ -> redirect 303 "/login"
}For rotation, use cookie_secrets_with_previous; new cookies are signed with
the current secret, while verification accepts previous secrets.
Static Files
Serve a directory under a URL prefix:
choose [
static_dir "/static" "src/static",
route GET "/" home,
] reqstatic_dir supports GET and HEAD, infers common content types, rejects
unsafe path segments, emits ETag and Last-Modified, handles conditional
requests, and supports single byte ranges. Unsupported multi-range requests are
ignored and receive the full response body.
Use static_dir_with to set Cache-Control or disable index-file lookup.
When index lookup is disabled, requests for the directory root return 404:
let options =
default_static_options
|> static_immutable_cache 31536000
static_dir_with options "/assets" "priv/assets" reqFor exact cache policies, use with_static_cache_control. Common helpers
include static_no_cache, static_no_store, static_public_cache, and
static_immutable_cache.
Use file_response or file_response_as when a route needs to serve one known
filesystem path.
For large files, use the streaming variants:
static_dir_streaming "/static" "src/static"
file_stream_response "src/static/cats/cat1.jpg"Streaming file responses avoid buffering the whole successful file response in
memory while preserving validators, HEAD, and single byte ranges.