88"""
99
1010try :
11- from typing import Callable , Protocol , Union , List , Tuple
11+ from typing import Callable , Protocol , Union , List , Set , Tuple
1212 from socket import socket
1313 from socketpool import SocketPool
1414except ImportError :
@@ -51,20 +51,30 @@ def __init__(
5151 self ._auths = []
5252 self ._buffer = bytearray (1024 )
5353 self ._timeout = 1
54- self .routes = _Routes ()
54+ self ._routes = _Routes ()
5555 self ._socket_source = socket_source
5656 self ._sock = None
5757 self .root_path = root_path
5858 self .stopped = False
5959
6060 self .debug = debug
6161
62- def route (self , path : str , methods : Union [str , List [str ]] = GET ) -> Callable :
62+ def route (
63+ self ,
64+ path : str ,
65+ methods : Union [str , Set [str ]] = GET ,
66+ * ,
67+ append_slash : bool = False ,
68+ ) -> Callable :
6369 """
6470 Decorator used to add a route.
6571
72+ If request matches multiple routes, the first matched one added will be used.
73+
6674 :param str path: URL path
6775 :param str methods: HTTP method(s): ``"GET"``, ``"POST"``, ``["GET", "POST"]`` etc.
76+ :param bool append_slash: If True, the route will be accessible with and without a
77+ trailing slash
6878
6979 Example::
7080
@@ -78,6 +88,14 @@ def route_func(request):
7888 def route_func(request):
7989 ...
8090
91+ # If you want to access URL with and without trailing slash, use append_slash=True
92+ @server.route("/example-with-slash", append_slash=True)
93+ # which is equivalent to
94+ @server.route("/example-with-slash")
95+ @server.route("/example-with-slash/")
96+ def route_func(request):
97+ ...
98+
8199 # Multiple methods can be specified
82100 @server.route("/example", [GET, POST])
83101 def route_func(request):
@@ -88,12 +106,13 @@ def route_func(request):
88106 def route_func(request, my_parameter):
89107 ...
90108 """
91- if isinstance (methods , str ):
92- methods = [methods ]
109+ if path .endswith ("/" ) and append_slash :
110+ raise ValueError ("Cannot use append_slash=True when path ends with /" )
111+
112+ methods = methods if isinstance (methods , set ) else {methods }
93113
94114 def route_decorator (func : Callable ) -> Callable :
95- for method in methods :
96- self .routes .add (_Route (path , method ), func )
115+ self ._routes .add (_Route (path , methods , append_slash ), func )
97116 return func
98117
99118 return route_decorator
@@ -294,7 +313,9 @@ def poll(self):
294313 _debug_incoming_request (request )
295314
296315 # Find a handler for the route
297- handler = self .routes .find_handler (_Route (request .path , request .method ))
316+ handler = self ._routes .find_handler (
317+ _Route (request .path , request .method )
318+ )
298319
299320 # Handle the request
300321 self ._handle_request (request , handler )
0 commit comments