Core Concepts & Behavior

Understanding how Fist processes requests will help you design better APIs and avoid common pitfalls.

The Trie Structure

Fist uses a Radix Trie (Prefix Tree) internally.

Path Normalization

Fist automatically handles common URL inconsistencies so you don’t have to write logic for them:

Precedence & Priority

When a request matches multiple possibilities (e.g., a static route and a wildcard), Fist follows this strict priority order:

  1. Exact Static Match
    • Example: /posts/new takes priority over /posts/:id.
  2. Dynamic Match
    • Example: /posts/:id matches if no static route matches.
  3. Backtracking
    • If a static segment matches partially but fails deeper down, Fist backtracks to check for dynamic matches at that level.

Constraints

The “Same Level” Constraint

Because of the Trie structure, you cannot register two different dynamic parameter names at the exact same position in the tree.

If you do, the last one defined will overwrite the parameter name for all handlers at that position.

❌ Conflicting (Last one wins):

fist.new()
|> fist.get("/api/:user_id/posts", handler_a)
|> fist.get("/api/:id/settings", handler_b)
// Result: Both handlers will receive "id" as the parameter key.
// In handler_a, dict.get(params, "user_id") will return Error(Nil).

✅ Recommended (Unique names or prefixes):

fist.new()
|> fist.get("/users/:user_id/posts", handler_a)
|> fist.get("/products/:product_id/settings", handler_b)
✨ Search Document