Mastering Fiber’s Radix Router: Method‑Specific Paths and Path Parameters
Learn how Fiber’s radix‑based router handles HTTP method‑specific routes and path parameters, the pitfalls of route ordering, and a hands‑on example to validate your setup.
01 Jun 2026, 03:45 UTC

Concrete Problem: Why Does My GET /users/:id Not Work After Adding a POST?
When you add a new POST route that shares the same path pattern as an existing GET route, you may find that the GET handler is no longer called. The culprit is often the order in which routes are registered in Fiber’s radix‑tree router.
How Fiber’s Router Works
Fiber builds its routing table as a radix tree (also called a compressed prefix tree). Each node represents a segment of the URL path. When a request arrives, Fiber walks this tree, matching segments one by one. The match is case‑sensitive and is performed separately for each HTTP method: GET, POST, PUT, etc. Thus, the same path can have distinct handlers for different verbs.
Path parameters are declared with a leading colon, e.g. /users/:id. During traversal, a node that starts with a colon matches any value for that segment. The matched value is stored in the request context’s Params map and can be retrieved with c.Params("id") or c.ParamsInt("id") for an integer.
Registering Method‑Specific Routes
To attach a handler to a particular HTTP method, Fiber offers dedicated methods: app.Get, app.Post, app.Put, etc. Internally, each call creates a separate leaf node under the same path pattern but keyed by the method. Because the router is a tree, the method is part of the node’s key, so no conflict arises between GET /users/:id and POST /users/:id.
However, the order of registration matters when the same pattern could match multiple routes. For example, a generic catch‑all route like app.Get("/:any", …) registered before a more specific app.Get("/users/:id", …) will always capture /users/123 and the specific handler will never run.
Capturing Path Parameters Safely
When a request matches /users/:id, Fiber extracts the value and places it into the context. A typical handler looks like this:
func getUser(c *fiber.Ctx) error {
id := c.Params("id") // string
// Optionally convert to int
// idInt, err := strconv.Atoi(id)
return c.JSON(fiber.Map{"user_id": id})
}
Because parameters are stored in a map, you can define multiple parameters in a single route, e.g. /orders/:orderId/items/:itemId, and retrieve each by name.
Ordering and Ambiguity: A Practical Test
Below is a minimal Go program that demonstrates method‑specific routing and parameter extraction. The code is intentionally simple so you can copy‑paste it into a file named main.go and run it with go run main.go.
package main
import (
"github.com/gofiber/fiber/v2"
)
func main() {
app := fiber.New()
// GET route with a path parameter
app.Get("/users/:id", func(c *fiber.Ctx) error {
id := c.Params("id")
return c.JSON(fiber.Map{"method": "GET", "id": id})
})
// POST route on the same path
app.Post("/users/:id", func(c *fiber.Ctx) error {
id := c.Params("id")
return c.JSON(fiber.Map{"method": "POST", "id": id})
})
// Catch‑all route that could shadow specific ones if registered first
app.Get("/:any", func(c *fiber.Ctx) error {
return c.SendString("Catch‑all handler")
})
app.Listen(3000)
}
After starting the server, you can verify the behavior with curl:
curl -i http://localhost:3000/users/42should return a JSON payload withmethod: GETandid: 42.curl -i -X POST http://localhost:3000/users/99should returnmethod: POSTandid: 99.- Requesting
curl -i http://localhost:3000/anythingwill hit the catch‑all route unless it is registered after the specific ones.
To check that the catch‑all does not override the specific routes, you can either:
- Move the
app.Get("/:any", …)line below the otherapp.Getregistrations, or - Remove it entirely for a focused test.
Trade‑Offs & Limitations
- Route Ordering: Because Fiber’s router is a tree, the first matching node wins. If you register a generic route before a specific one, the specific handler will be unreachable. Keep specific routes at the top of your file or use explicit ordering.
- Case Sensitivity: Paths are matched case‑sensitively.
/Usersand/usersare distinct. If your API is case‑insensitive, you must enforce it yourself or use middleware to normalize the path. - Nested Parameters: A route like
/a/:b/c/:dcan be ambiguous if you also register/a/:x/:y. Fiber resolves based on the tree depth, but careful design avoids accidental shadowing. - Performance: For very large routing tables, the radix tree can still become a hotspot. Fiber’s router is highly optimized, but profiling is recommended for production workloads.
Actionable Takeaways
- Register specific routes first. Place complex patterns before generic catch‑alls.
- Test each method separately. Use
curl -X METHODto confirm the correct handler runs. - Validate parameters. Always check that
c.Params("name")returns a non‑empty string before using it. - When deploying, keep your route definitions in a single file or module to avoid accidental reordering during merges.
- Use Fiber’s built‑in
c.ParamsIntfor numeric IDs to catch conversion errors early.
By following these practices, you can leverage Fiber’s powerful routing system to build clean, method‑aware APIs that correctly capture path parameters without unintended shadowing.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.