Skip to content

Commit 8e2967b

Browse files
committed
Changed how routes are mapped to handler functions, added _HTTPRoutes
Added option to provide regex-like URLs using <> brackets
1 parent c1a47ab commit 8e2967b

1 file changed

Lines changed: 63 additions & 4 deletions

File tree

adafruit_httpserver/route.py

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
* Author(s): Dan Halbert, Michał Pokusa
88
"""
99

10+
try:
11+
from typing import Callable, List, Union
12+
except ImportError:
13+
pass
14+
15+
import re
16+
1017
from .methods import HTTPMethod
1118

1219

@@ -15,14 +22,66 @@ class _HTTPRoute:
1522

1623
def __init__(self, path: str = "", method: HTTPMethod = HTTPMethod.GET) -> None:
1724

18-
self.path = path
25+
contains_regex = re.search(r"<\w*>", path)
26+
27+
self.path = path if not contains_regex else re.sub(r"<\w*>", r"([^/]*)", path)
1928
self.method = method
29+
self.regex = contains_regex
30+
31+
def matches(self, other: "_HTTPRoute") -> bool:
32+
"""
33+
Checks if the route matches the other route.
34+
35+
If the route contains parameters, it will check if the other route contains values for them.
36+
"""
2037

21-
def __hash__(self) -> int:
22-
return hash(self.method) ^ hash(self.path)
38+
if self.regex or other.regex:
39+
return re.match(self.path, other.path) and self.method == other.method
2340

24-
def __eq__(self, other: "_HTTPRoute") -> bool:
2541
return self.method == other.method and self.path == other.path
2642

2743
def __repr__(self) -> str:
2844
return f"HTTPRoute(path={repr(self.path)}, method={repr(self.method)})"
45+
46+
47+
class _HTTPRoutes:
48+
"""A collection of routes and their corresponding handlers."""
49+
50+
def __init__(self) -> None:
51+
self._routes: List[_HTTPRoute] = []
52+
self._handlers: List[Callable] = []
53+
54+
def add(self, route: _HTTPRoute, handler: Callable):
55+
"""Adds a route and its handler to the collection."""
56+
57+
self._routes.append(route)
58+
self._handlers.append(handler)
59+
60+
def find_handler(self, route: _HTTPRoute) -> Union[Callable, None]:
61+
"""
62+
Finds a handler for a given route.
63+
64+
If route used URL parameters, the handler will be wrapped to pass the parameters to the
65+
handler.
66+
67+
Example::
68+
69+
@server.route("/example/<my_parameter>", HTTPMethod.GET)
70+
def route_func(request, my_parameter):
71+
...
72+
request.path == "/example/123" # True
73+
my_parameter == "123" # True
74+
"""
75+
76+
try:
77+
matched_route = next(filter(lambda r: r.matches(route), self._routes))
78+
except StopIteration:
79+
return None
80+
81+
handler = self._handlers[self._routes.index(matched_route)]
82+
args = re.match(matched_route.path, route.path).groups()
83+
84+
def wrapper(request):
85+
return handler(request, *args)
86+
87+
return wrapper

0 commit comments

Comments
 (0)