diff --git a/sanic/router.py b/sanic/router.py
index e25572fb..1f26171e 100644
--- a/sanic/router.py
+++ b/sanic/router.py
@@ -149,7 +149,22 @@ class Router:
handler=view, methods=methods.union(route.methods))
return route
- route = self.routes_all.get(uri)
+ if parameters:
+ # TODO: This is too complex, we need to reduce the complexity
+ if properties['unhashable']:
+ routes_to_check = self.routes_always_check
+ ndx, route = self.check_dynamic_route_exists(
+ pattern, routes_to_check)
+ else:
+ routes_to_check = self.routes_dynamic[url_hash(uri)]
+ ndx, route = self.check_dynamic_route_exists(
+ pattern, routes_to_check)
+ if ndx != -1:
+ # Pop the ndx of the route, no dups of the same route
+ routes_to_check.pop(ndx)
+ else:
+ route = self.routes_all.get(uri)
+
if route:
route = merge_route(route, methods, handler)
else:
@@ -165,6 +180,14 @@ class Router:
else:
self.routes_static[uri] = route
+ @staticmethod
+ def check_dynamic_route_exists(pattern, routes_to_check):
+ for ndx, route in enumerate(routes_to_check):
+ if route.pattern == pattern:
+ return ndx, route
+ else:
+ return -1, None
+
def remove(self, uri, clean_cache=True, host=None):
if host is not None:
uri = host + uri
diff --git a/tests/test_dynamic_routes.py b/tests/test_dynamic_routes.py
new file mode 100644
index 00000000..24ba79b5
--- /dev/null
+++ b/tests/test_dynamic_routes.py
@@ -0,0 +1,46 @@
+from sanic import Sanic
+from sanic.response import text
+from sanic.utils import sanic_endpoint_test
+from sanic.router import RouteExists
+import pytest
+
+
+@pytest.mark.parametrize("method,attr, expected", [
+ ("get", "text", "OK1 test"),
+ ("post", "text", "OK2 test"),
+ ("put", "text", "OK2 test"),
+ ("delete", "status", 405),
+])
+def test_overload_dynamic_routes(method, attr, expected):
+ app = Sanic('test_dynamic_route')
+
+ @app.route('/overload/', methods=['GET'])
+ async def handler1(request, param):
+ return text('OK1 ' + param)
+
+ @app.route('/overload/', methods=['POST', 'PUT'])
+ async def handler2(request, param):
+ return text('OK2 ' + param)
+
+ request, response = sanic_endpoint_test(
+ app, method, uri='/overload/test')
+ assert getattr(response, attr) == expected
+
+
+def test_overload_dynamic_routes_exist():
+ app = Sanic('test_dynamic_route')
+
+ @app.route('/overload/', methods=['GET'])
+ async def handler1(request, param):
+ return text('OK1 ' + param)
+
+ @app.route('/overload/', methods=['POST', 'PUT'])
+ async def handler2(request, param):
+ return text('OK2 ' + param)
+
+ # if this doesn't raise an error, than at least the below should happen:
+ # assert response.text == 'Duplicated'
+ with pytest.raises(RouteExists):
+ @app.route('/overload/', methods=['PUT', 'DELETE'])
+ async def handler3(request):
+ return text('Duplicated')