app.Get("/items", listItems)
app.Post("/items", createItem)
app.Put("/items/{id}", updateItem)
app.Delete("/items/{id}", deleteItem)Methods map one-to-one to registrars: Get/Head/Post/Put/Patch/Delete/Options. Above, listItems etc. are httpsrv.Handler (i.e. func(c httpsrv.Ctx) error). Methods are independent — with only a GET route, a POST to the same path returns 404.
Registrars return the Router, so you can chain:
app.Get("/a", hA).
Get("/b", hB).
Post("/c", hC)Define a parameter segment with braces and read it in the handler via c.Params(name) (backed by the stdlib r.PathValue):
app.Get("/users/{id}", func(c httpsrv.Ctx) error {
return c.SendString("id=" + c.Params("id"))
})- A parameter matches
[^/]+, i.e. a single path segment (no/). - Multiple parameters are supported:
app.Get("/posts/{post_id}/comments/{comment_id}", func(c httpsrv.Ctx) error {
return c.SendString(c.Params("post_id") + " " + c.Params("comment_id"))
})
// GET /posts/5/comments/22 -> 5 22- The parameter value keeps its original content, e.g. for
GET /users/news.htmlthe{id}isnews.html.
⚠️ Only the{name}syntax is supported;:nameis literal and not treated as a parameter.
{*name} matches the rest of the path (including /) and must be the last segment of the pattern:
app.Get("/files/{*path}", func(c httpsrv.Ctx) error {
return c.SendString("file=" + c.Params("path"))
})
// GET /files/a.txt -> path = "a.txt"
// GET /files/css/main.css -> path = "css/main.css"
// GET /files/deep/nested/x -> path = "deep/nested/x"
// GET /files -> path = "" (empty remainder matches)
// GET /files/ -> path = "" (CleanPath drops the trailing /)- The catch-all value has no leading
/(e.g.css/main.css). - An empty remainder matches: a catch-all matches the rest of the path, including an empty one, so
/files/{*path}matches/files(path = "") and/*matches the root/(* = ""). A plain{name}parameter still requires a non-empty value. - Besides its named key, a catch-all is also exposed under the conventional key
"*", readable viac.Params("*")(mirroring fiber'sc.Params("*")convention). - Priority: static segment >
{name}parameter >{*name}catch-all, independent of registration order. - Nothing may follow
{*name}; e.g./files/{*path}/extrapanics at registration. - Two differently named catch-alls at the same position conflict (e.g.
/files/{*a}vs/files/{*b}); re-registering the same name overwrites the handler. - Unnamed
/*wildcard: a bare*segment is an unnamed catch-all (gofiber v3 style), equivalent to{*}, whose value is likewise exposed under"*". Common for static files:app.Get("/*", static.New("./public")),app.Get("/static/*", ...).
A static segment always beats a parameter or catch-all at the same position, independent of registration order:
app.Get("/users/profile", showProfile) // static
app.Get("/users/{id}", showUser) // parameter
app.Get("/users/{*rest}", showRest) // catch-allGET /users/profile -> showProfile (static hit)
GET /users/42 -> showUser (parameter hit)
GET /users/a/b/c -> showRest (catch-all hit)
Matching is case-sensitive:
app.Get("/Users", h)
// GET /Users -> match
// GET /users -> 404Both registration and matching normalize the path with path.Clean: collapsing duplicate slashes, resolving ./.., and ensuring a leading /. So these are equivalent:
app.Get("//api//users/", h)
// equivalent to app.Get("/api/users", h)Request paths are normalized before matching as well.
app.All("/healthz", func(c httpsrv.Ctx) error {
return c.SendString("ok")
})
// GET/POST/PUT/... /healthz all matchTo surface errors early, an invalid path pattern panics (already-registered routes are unaffected):
app.Get("/users/{id", h) // panic: unclosed '{'
app.Get("/users/{}", h) // panic: empty parameter name
app.Get("/{a}{b}", h) // panic: multiple parameters in one segment
app.Get("/files/{*path}/extra", h) // panic: catch-all must be the last segment