Skip to content

Commit a424d27

Browse files
committed
Added ... and .... wildcards
1 parent 191e91c commit a424d27

File tree

4 files changed

+47
-8
lines changed

4 files changed

+47
-8
lines changed

adafruit_httpserver/route.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ def __init__(
3131
self.parameters_names = [
3232
name[1:-1] for name in re.compile(r"/[^<>]*/?").split(path) if name != ""
3333
]
34-
self.path = re.sub(r"<\w*>", r"([^/]*)", path) + ("/?" if append_slash else "")
34+
self.path = re.sub(r"<\w+>", r"([^/]+)", path).replace("....", r".+").replace(
35+
"...", r"[^/]+"
36+
) + ("/?" if append_slash else "")
3537
self.methods = methods if isinstance(methods, set) else {methods}
3638

3739
@staticmethod
@@ -54,10 +56,12 @@ def match(self, other: "_Route") -> Tuple[bool, List[str]]:
5456
5557
Examples::
5658
57-
route = _Route("/example", GET)
59+
route = _Route("/example", GET, True)
5860
59-
other1 = _Route("/example", GET)
60-
route.matches(other1) # True, []
61+
other1a = _Route("/example", GET)
62+
other1b = _Route("/example/", GET)
63+
route.matches(other1a) # True, []
64+
route.matches(other1b) # True, []
6165
6266
other2 = _Route("/other-example", GET)
6367
route.matches(other2) # False, []
@@ -71,6 +75,16 @@ def match(self, other: "_Route") -> Tuple[bool, List[str]]:
7175
7276
other2 = _Route("/other-example", GET)
7377
route.matches(other2) # False, []
78+
79+
...
80+
81+
route1 = _Route("/example/.../something", GET)
82+
other1 = _Route("/example/123/something", GET)
83+
route1.matches(other1) # True, []
84+
85+
route2 = _Route("/example/..../something", GET)
86+
other2 = _Route("/example/123/456/something", GET)
87+
route2.matches(other2) # True, []
7488
"""
7589

7690
if not other.methods.issubset(self.methods):

adafruit_httpserver/server.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,15 @@ def route_func(request):
102102
...
103103
104104
# URL parameters can be specified
105-
@server.route("/example/<my_parameter>", GET)
105+
@server.route("/example/<my_parameter>", GET) e.g. /example/123
106106
def route_func(request, my_parameter):
107107
...
108+
109+
# It is possible to use wildcard that can match any number of path segments
110+
@server.route("/example/.../something", GET) # e.g. /example/123/something
111+
@server.route("/example/..../something", GET) # e.g. /example/123/456/something
112+
def route_func(request):
113+
...
108114
"""
109115
if path.endswith("/") and append_slash:
110116
raise ValueError("Cannot use append_slash=True when path ends with /")

docs/examples.rst

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ To use it, you need to set the ``chunked=True`` when creating a ``Response`` obj
154154
:emphasize-lines: 21-26
155155
:linenos:
156156

157-
URL parameters
158-
--------------
157+
URL parameters and wildcards
158+
----------------------------
159159

160160
Alternatively to using query parameters, you can use URL parameters.
161161
They are a better choice when you want to perform different actions based on the URL.
@@ -176,9 +176,16 @@ In the example below the second route has only one URL parameter, so the ``actio
176176
Keep in mind that URL parameters are always passed as strings, so you need to convert them to the desired type.
177177
Also note that the names of the function parameters **have to match** with the ones used in route, but they **do not have to** be in the same order.
178178

179+
It is also possible to specify a wildcard route:
180+
181+
- ``...`` - matches one path segment, e.g ``/api/...`` will match ``/api/123``, but **not** ``/api/123/456``
182+
- ``....`` - matches multiple path segments, e.g ``/api/....`` will match ``/api/123`` and ``/api/123/456``
183+
184+
In both cases, wildcards will not match empty path segment, so ``/api/.../users`` will match ``/api/v1/users``, but not ``/api//users`` or ``/api/users``.
185+
179186
.. literalinclude:: ../examples/httpserver_url_parameters.py
180187
:caption: examples/httpserver_url_parameters.py
181-
:emphasize-lines: 30-34
188+
:emphasize-lines: 30-34,54-55
182189
:linenos:
183190

184191
Authentication

examples/httpserver_url_parameters.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,16 @@ def perform_action(
5151
response.send(f"Action ({action}) performed on device with ID: {device_id}")
5252

5353

54+
@server.route("/device/.../status", append_slash=True)
55+
@server.route("/device/....", append_slash=True)
56+
def device_status(request: Request):
57+
"""
58+
Returns the status of all devices no matter what their ID is.
59+
Unknown commands also return the status of all devices.
60+
"""
61+
62+
with Response(request, content_type="text/plain") as response:
63+
response.send("Status of all devices: ...")
64+
65+
5466
server.serve_forever(str(wifi.radio.ipv4_address))

0 commit comments

Comments
 (0)