diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cdc001..bb5fe82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## v0.5.12 +* New feature: If a route has `matchSubPaths = true`, the requested subpath can be assigned to a parameter (see issue #36). + ## v0.5.11 * Minor performance fix: Redstone.dart shouldn't create a new `shelf.Pipeline` per request. diff --git a/lib/server.dart b/lib/server.dart index 1ddf916..7d09750 100644 --- a/lib/server.dart +++ b/lib/server.dart @@ -459,7 +459,7 @@ void setUp([List libraries]) { _scanHandlers(libraries); } catch (e) { _handleError("Failed to configure handlers.", e); - throw e; + rethrow; } } diff --git a/lib/src/setup_impl.dart b/lib/src/setup_impl.dart index 8091321..0f81722 100644 --- a/lib/src/setup_impl.dart +++ b/lib/src/setup_impl.dart @@ -57,20 +57,13 @@ class _Target { UrlMatch match(Uri uri) { UrlMatch match = urlTemplate.match(uri.path); if (match != null) { - if (route.matchSubPaths) { - if (uri.path.endsWith("/") || match.tail.startsWith("/")) { - return match; - } - } else { - if (match.tail.isEmpty) { - return match; - } + if (match.tail.isEmpty) { + return match; + } else if (route.matchSubPaths && + (uri.path.endsWith("/") || match.tail.startsWith("/"))) { + return match; } } - - if (match != null && match.tail.isEmpty) { - return match; - } return null; } @@ -721,6 +714,7 @@ void _configureTarget(_ServerMetadataImpl serverMetadata, var responseProcessors = null; var wrapper = null; + var specialPathParam = null; var caller = (UrlMatch match, Request request) { @@ -771,6 +765,10 @@ void _configureTarget(_ServerMetadataImpl serverMetadata, return new Future(() { var pathParams = match.parameters; + + if (specialPathParam != null) { + pathParams[specialPathParam] = pathParams[specialPathParam] + match.tail; + } var posParams = []; var namedParams = {}; @@ -815,12 +813,25 @@ void _configureTarget(_ServerMetadataImpl serverMetadata, }; - String url = route.urlTemplate; + String url = route.urlTemplate.trim(); if (urlPrefix != null) { url = _joinUrl(urlPrefix, url); } + + var originalUrl = url; + if (url.endsWith("*")) { + url = url.substring(0, url.length - 1); + } UrlTemplate urlTemplate = new UrlTemplate(url); + + if (route.matchSubPaths && urlTemplate.urlParameterNames().isNotEmpty) { + var lastParam = urlTemplate.urlParameterNames().last; + if (originalUrl.endsWith(":$lastParam*")) { + specialPathParam = lastParam; + } + } + _Target target; if (paramProcessors.bodyType == null) { target = new _Target(urlTemplate, handlerName, caller, route); diff --git a/pubspec.yaml b/pubspec.yaml index 8189372..b7bf03f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: redstone -version: 0.5.11 +version: 0.5.12 author: Luiz Mineo description: A metadata driven microframework for Dart homepage: http://redstonedart.org @@ -9,7 +9,7 @@ dependencies: collection: '>=0.9.3+1 <0.10.0' crypto: '>=0.9.0 <0.10.0' grinder: '>=0.5.2 <0.6.0' - route_hierarchical: '>=0.4.21 <0.5.0' + route_hierarchical: '>=0.4.22 <0.5.0' di: ">=2.0.1 <3.0.0" shelf: ">=0.5.4+2 <0.6.0" mime: ">=0.9.0+1 <0.10.0" diff --git a/test/server_tests.dart b/test/server_tests.dart index 7221231..da81b8e 100644 --- a/test/server_tests.dart +++ b/test/server_tests.dart @@ -35,6 +35,8 @@ main() { var req = new MockRequest("/path/subpath"); var req2 = new MockRequest("/path/anotherpath"); var req3 = new MockRequest("/paths"); + var req4 = new MockRequest("/path2/sub/path"); + var req5 = new MockRequest("/path3/sub/path"); return app.dispatch(req).then((resp) { expect(resp.mockContent, equals("sub_route")); @@ -42,6 +44,10 @@ main() { expect(resp.mockContent, equals("main_route")); }).then((_) => app.dispatch(req3)).then((resp) { expect(resp.statusCode, equals(404)); + }).then((_) => app.dispatch(req4)).then((resp) { + expect(resp.mockContent, equals("sub")); + }).then((_) => app.dispatch(req5)).then((resp) { + expect(resp.mockContent, equals("sub/path")); }); }); diff --git a/test/services/routes.dart b/test/services/routes.dart index 8f60294..9d880f8 100644 --- a/test/services/routes.dart +++ b/test/services/routes.dart @@ -9,6 +9,12 @@ mainRoute() => "main_route"; @app.Route("/path/subpath") subRoute() => "sub_route"; +@app.Route("/path2/:param", matchSubPaths: true) +mainRouteWithParam(String param) => param; + +@app.Route("/path3/:param*", matchSubPaths: true) +mainRouteWithSpecialParam(String param) => param; + @app.Route("/handler_by_method") getHandler() => "get_handler";