Routing is the core mechanism that connects HTTP requests to the appropriate code handlers. In a lightweight Python web framework, implementing efficient and flexible routing allows you to build clean URLs, handle dynamic parameters, and organize your app logically.
What Routing Does
When a client sends a request, the framework must decide which function or method will process it. Routing takes the request path and HTTP method, then matches it against predefined patterns to find the correct handler.
Basic Route Matching
The simplest routing matches fixed paths:
-
/home
→ serves home page -
/about
→ serves about page
You can store routes in a dictionary keyed by path:
routes = {
"/": home_handler,
"/about": about_handler,
}
Lookup is then a quick dictionary access.
Dynamic Routes with Parameters
Real apps need dynamic routes like /users/42
where 42
is a user ID.
You can define routes with placeholders like /users/<id>
and extract parameters using pattern matching.
One way is to convert route patterns to regular expressions:
import re
class Router:
def __init__(self):
self.routes = []
def add(self, pattern, handler):
regex_pattern = re.sub(r"<(\w+)>", r"(?P<\1>[^/]+)", pattern)
regex = re.compile(f"^{regex_pattern}$")
self.routes.append((regex, handler))
def match(self, path):
for regex, handler in self.routes:
match = regex.match(path)
if match:
return handler, match.groupdict()
return None, {}
Example Usage
router = Router()
def user_handler(params):
user_id = params.get("id")
return f"User profile for {user_id}"
router.add("/users/<id>", user_handler)
path = "/users/42"
handler, params = router.match(path)
if handler:
response = handler(params)
else:
response = "404 Not Found"
Handling HTTP Methods
You can extend routing to consider HTTP methods (GET, POST, etc.) by storing routes as:
routes = {
("GET", "/users/<id>"): user_handler,
("POST", "/users"): create_user_handler,
}
Modify your router to match method + path.
Supporting Route Middleware
Middleware lets you process requests before or after handlers, for tasks like authentication or logging.
Attach middleware functions to routes or globally and run them in sequence, passing the request context along.
Performance Considerations
- Compile regex once when adding routes
- Organize routes to match static paths first
- Cache frequently accessed routes
When to Keep It Simple vs Use a Library
For small projects, a simple Router class works well. For bigger apps, consider using mature routing libraries like Werkzeug or Starlette’s router.
Wrap-Up
Routing is essential for any web framework. By efficiently matching paths and methods, supporting dynamic parameters, and integrating middleware, your lightweight Python framework can serve both static and complex dynamic content cleanly.
Want to dive deeper? Check out my 20-page PDF guide: Building a Lightweight Python Web Framework from Scratch
Top comments (0)