Skip to content

Commit 5c30a2a

Browse files
committed
Added as_route decorator as shorthand for creating Route objects
1 parent e34d27d commit 5c30a2a

File tree

3 files changed

+68
-11
lines changed

3 files changed

+68
-11
lines changed

adafruit_httpserver/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
SSEResponse,
6262
Websocket,
6363
)
64-
from .route import Route
64+
from .route import Route, as_route
6565
from .server import Server
6666
from .status import (
6767
Status,

adafruit_httpserver/route.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,55 @@ def match(self, other: "Route") -> Tuple[bool, Dict[str, str]]:
111111
def __repr__(self) -> str:
112112
path = repr(self.path)
113113
methods = repr(self.methods)
114+
handler = repr(self.handler)
114115

115-
return f"Route(path={path}, methods={methods})"
116+
return f"Route({path=}, {methods=}, {handler=})"
117+
118+
119+
def as_route(
120+
path: str,
121+
methods: Union[str, Set[str]] = GET,
122+
*,
123+
append_slash: bool = False,
124+
) -> "Callable[[Callable[..., Response]], Route]":
125+
"""
126+
Decorator used to convert a function into a ``Route`` object.
127+
128+
It is a shorthand for manually creating a ``Route`` object, that can be used only one time
129+
per function. Later it can be imported and registered in the ``Server``.
130+
131+
:param str path: URL path
132+
:param str methods: HTTP method(s): ``"GET"``, ``"POST"``, ``["GET", "POST"]`` etc.
133+
:param bool append_slash: If True, the route will be accessible with and without a
134+
trailing slash
135+
136+
Example::
137+
138+
# Default method is GET
139+
@as_route("/example")
140+
def some_func(request):
141+
...
142+
143+
some_func # Route(path="/example", methods={"GET"}, handler=<function some_func at 0x...>)
144+
145+
# If a route in another file, you can import it and register it to the server
146+
147+
from .routes import some_func
148+
149+
...
150+
151+
server.add_routes([
152+
some_func,
153+
])
154+
"""
155+
156+
def route_decorator(func: Callable) -> Route:
157+
if isinstance(func, Route):
158+
raise ValueError("as_route can be used only once per function.")
159+
160+
return Route(path, methods, func, append_slash=append_slash)
161+
162+
return route_decorator
116163

117164

118165
class _Routes:

examples/httpserver_neopixel.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import socketpool
88
import wifi
99

10-
from adafruit_httpserver import Server, Route, Request, Response, GET, POST
10+
from adafruit_httpserver import Server, Route, as_route, Request, Response, GET, POST
1111

1212

1313
pool = socketpool.SocketPool(wifi.radio)
@@ -16,6 +16,7 @@
1616
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
1717

1818

19+
# This is the simplest way to register a route. It uses the Server object in current scope.
1920
@server.route("/change-neopixel-color", GET)
2021
def change_neopixel_color_handler_query_params(request: Request):
2122
"""Changes the color of the built-in NeoPixel using query/GET params."""
@@ -31,7 +32,9 @@ def change_neopixel_color_handler_query_params(request: Request):
3132
return Response(request, f"Changed NeoPixel to color ({r}, {g}, {b})")
3233

3334

34-
@server.route("/change-neopixel-color", POST)
35+
# This is another way to register a route. It uses the decorator that converts the function into
36+
# a Route object that can be imported and registered later.
37+
@as_route("/change-neopixel-color", POST)
3538
def change_neopixel_color_handler_post_body(request: Request):
3639
"""Changes the color of the built-in NeoPixel using POST body."""
3740

@@ -54,6 +57,13 @@ def change_neopixel_color_handler_post_json(request: Request):
5457
return Response(request, f"Changed NeoPixel to color ({r}, {g}, {b})")
5558

5659

60+
# You can always manually create a Route object and import or register it later.
61+
# Using this approach you can also use the same handler for multiple routes.
62+
post_json_route = Route(
63+
"/change-neopixel-color/json", GET, change_neopixel_color_handler_post_json
64+
)
65+
66+
5767
def change_neopixel_color_handler_url_params(
5868
request: Request, r: str = "0", g: str = "0", b: str = "0"
5969
):
@@ -66,17 +76,17 @@ def change_neopixel_color_handler_url_params(
6676
return Response(request, f"Changed NeoPixel to color ({r}, {g}, {b})")
6777

6878

69-
url_params_route = Route(
70-
"/change-neopixel-color/<r>/<g>/<b>", GET, change_neopixel_color_handler_url_params
71-
)
72-
73-
# Alternative way of registering routes.
79+
# Registering Route objects
7480
server.add_routes(
7581
[
82+
change_neopixel_color_handler_post_body,
83+
post_json_route,
84+
# You can also register a inline created Route object
7685
Route(
77-
"/change-neopixel-color/json", GET, change_neopixel_color_handler_post_json
86+
path="/change-neopixel-color/<r>/<g>/<b>",
87+
methods=GET,
88+
handler=change_neopixel_color_handler_url_params,
7889
),
79-
url_params_route,
8090
]
8191
)
8292

0 commit comments

Comments
 (0)