Core Concepts & Behavior

Understanding how Fist processes requests will help you design clean APIs and understand its deterministic routing engine.

The Trie Structure

Fist uses a Radix Trie (Prefix Tree) internally:

Path Normalization & Defensive Security (RFC 3986)

Fist automatically normalizes and sanitizes paths before matching:

Precedence & Priority

When a request URL could potentially match multiple routes, Fist resolves conflicts using a strict 3-tier specificity hierarchy:

\mathbf{Static} \;\;>\;\; \mathbf{Dynamic \; (:param)} \;\;>\;\; \mathbf{Wildcard \; (*param)}

  1. Exact Static Match:
    • /posts/new takes priority over /posts/:id and /posts/*rest.
  2. Dynamic Match (:param):
    • /users/:id matches single segments if no static route matches.
  3. Wildcard Catch-All (*param):
    • /static/*filepath matches all remaining segments if neither static nor dynamic branches match.
  4. Deep Backtracking:
    • If traversal down a static or dynamic branch hits a dead-end without finding a handler, Fist automatically backtracks to ancestor wildcard catch-alls to check for a looser match.

Fail-Fast Safety & Collision Protection

Fist embraces a strict Fail-Fast design philosophy. Ambiguous routes, duplicate endpoints, and conflicting segment names panic immediately at startup rather than silently overwriting each other.

1. Duplicate Routes Panic

Registering the exact same HTTP method and path twice on a router (or combining them via fist.merge or fist.mount) causes an immediate runtime panic:

// 💥 Panics: duplicate route already registered
fist.new()
|> fist.get("/endpoint", handler_v1)
|> fist.get("/endpoint", handler_v2)

2. Conflicting Dynamic Parameter Names Panic

Because a Radix Trie node can only bind one dynamic parameter name per level, defining different names at the same level panics:

// 💥 Panics: cannot register ':user_id' because ':id' is already registered at this level
fist.new()
|> fist.get("/users/:id/profile", handler_a)
|> fist.get("/users/:user_id/settings", handler_b)

✅ Solution: Use consistent parameter names (/users/:id/profile and /users/:id/settings). When identical names are used, branches merge cleanly.

3. Wildcard Rules & Invariants

✨ Search Document