A Router by Hand
Intuition
A web framework's first job is routing: given GET /items/42, find the function that
handles it and call it with item_id=42. Writing a small router yourself shows what
@app.get("/items/{item_id}") does in FastAPI (FA-08).
Precise explanation
- A pattern is a path split into segments;
{name}captures a segment as a string and{name:int}converts it to an int:"/items/{item_id:int}". - A path matches a pattern when both have the same number of segments and every literal segment is equal.
- Dispatch rules (in this order):
- No pattern matches the path → 404 Not Found.
- Patterns match, but none for this method → 405 Method Not Allowed, with an
allowheader listing the allowed methods (sorted, comma-separated). - A parameter fails conversion (e.g.
abcfor:int) → 422 with an error located at["path", "item_id"](FastAPI's behaviour). - Otherwise call the handler with the converted path parameters as keyword arguments, plus
query=the query dict. A handler returns a dict (status 200) or a(status, dict)tuple.
- Routes are tried in registration order; the first match wins, so register
/users/mebefore/users/{name}. - Decorator registration (PY-17):
@router.route("GET", "/items")stores the function and returns it unchanged.
Worked example
router = Router()
@router.route("GET", "/items/{item_id:int}")
def get_item(item_id, query):
return {"item_id": item_id}
router.dispatch("GET", "/items/42") # (200, {}, {"item_id": 42})
router.dispatch("DELETE", "/items/42") # (405, {"allow": "GET"}, {"detail": "Method Not Allowed"})
router.dispatch("GET", "/items/abc") # (422, {}, {"detail": [{"loc": ["path", "item_id"], ...}]})
Common mistakes
- Returning 404 when the path exists but the method does not (that is 405).
- Matching
/items/42/extraagainst/items/{id}because of a prefix check. - Converting parameters before knowing the method is allowed.
Why this matters
FastAPI performs exactly these steps, plus validation of query parameters and bodies, before your function runs.
References
- FastAPI Tutorial: Path Parameters — FastAPI (Sebastián Ramírez) (
S071) - RFC 9110: HTTP Semantics — IETF (Fielding, Nottingham, Reschke) (
S067)