diff --git a/lib/src/http/request_context.dart b/lib/src/http/request_context.dart index ce976759..da2beca5 100644 --- a/lib/src/http/request_context.dart +++ b/lib/src/http/request_context.dart @@ -73,7 +73,7 @@ class RequestContext extends Extensible { context.contentType = request.headers.contentType; context.remoteAddress = request.connectionInfo.remoteAddress; context.params = parameters; - context.path = request.uri.toString(); + context.path = request.uri.toString().replaceAll("?" + request.uri.query, "").replaceAll(new RegExp(r'\/+$'), ''); context.route = sourceRoute; context.session = request.session; context.underlyingRequest = request; diff --git a/lib/src/http/server.dart b/lib/src/http/server.dart index 90e2643a..2a44f126 100644 --- a/lib/src/http/server.dart +++ b/lib/src/http/server.dart @@ -52,7 +52,7 @@ class Angel extends Routable { server.listen((HttpRequest request) async { String req_url = - request.uri.toString().replaceAll(new RegExp(r'\/+$'), ''); + request.uri.toString().replaceAll("?" + request.uri.query, "").replaceAll(new RegExp(r'\/+$'), ''); if (req_url.isEmpty) req_url = '/'; RequestContext req = await RequestContext.from(request, {}, this, null); ResponseContext res = await ResponseContext.from(request.response, this); @@ -95,7 +95,7 @@ class Angel extends Routable { if (!canContinue) break; if (route.matcher.hasMatch(req_url) && (request.method == route.method || route.method == '*')) { - req.params = route.parseParameters(request.uri.toString()); + req.params = route.parseParameters(req_url); req.route = route; for (var handler in route.handlers) { diff --git a/lib/src/http/service.dart b/lib/src/http/service.dart index 243cc2fe..72340bdc 100644 --- a/lib/src/http/service.dart +++ b/lib/src/http/service.dart @@ -60,22 +60,46 @@ class Service extends Routable { Service() : super() { Map restProvider = {'provider': Providers.REST}; + Middleware indexMiddleware = _getAnnotation(this.index, Middleware); get('/', (req, res) async { return await this.index(mergeMap([req.query, restProvider])); - }); + }, middleware: (indexMiddleware == null) ? [] : indexMiddleware.handlers); - post('/', (req, res) async => await this.create(req.body, restProvider)); + Middleware createMiddleware = _getAnnotation(this.create, Middleware); + post('/', (req, res) async => await this.create(req.body, restProvider), + middleware: + (createMiddleware == null) ? [] : createMiddleware.handlers); - get('/:id', (req, res) async => - await this.read(req.params['id'], mergeMap([req.query, restProvider]))); + Middleware readMiddleware = _getAnnotation(this.read, Middleware); - patch('/:id', (req, res) async => await this.modify( - req.params['id'], req.body, restProvider)); + get( + '/:id', + (req, res) async => await this + .read(req.params['id'], mergeMap([req.query, restProvider])), + middleware: (readMiddleware == null) ? [] : readMiddleware.handlers); - post('/:id', (req, res) async => await this.update( - req.params['id'], req.body, restProvider)); + Middleware modifyMiddleware = _getAnnotation(this.modify, Middleware); + patch( + '/:id', + (req, res) async => + await this.modify(req.params['id'], req.body, restProvider), + middleware: + (modifyMiddleware == null) ? [] : modifyMiddleware.handlers); - delete('/:id', (req, res) async => await this.remove( - req.params['id'], mergeMap([req.query, restProvider]))); + Middleware updateMiddleware = _getAnnotation(this.update, Middleware); + post( + '/:id', + (req, res) async => + await this.update(req.params['id'], req.body, restProvider), + middleware: + (updateMiddleware == null) ? [] : updateMiddleware.handlers); + + Middleware removeMiddleware = _getAnnotation(this.remove, Middleware); + delete( + '/:id', + (req, res) async => await this + .remove(req.params['id'], mergeMap([req.query, restProvider])), + middleware: + (removeMiddleware == null) ? [] : removeMiddleware.handlers); } -} \ No newline at end of file +} diff --git a/lib/src/http/service_hooked.dart b/lib/src/http/service_hooked.dart index b3025980..ce744455 100644 --- a/lib/src/http/service_hooked.dart +++ b/lib/src/http/service_hooked.dart @@ -6,29 +6,32 @@ class HookedService extends Service { final Service inner; HookedServiceEventDispatcher beforeIndexed = - new HookedServiceEventDispatcher(); + new HookedServiceEventDispatcher(); HookedServiceEventDispatcher beforeRead = new HookedServiceEventDispatcher(); HookedServiceEventDispatcher beforeCreated = - new HookedServiceEventDispatcher(); + new HookedServiceEventDispatcher(); HookedServiceEventDispatcher beforeModified = - new HookedServiceEventDispatcher(); + new HookedServiceEventDispatcher(); HookedServiceEventDispatcher beforeUpdated = - new HookedServiceEventDispatcher(); + new HookedServiceEventDispatcher(); HookedServiceEventDispatcher beforeRemoved = - new HookedServiceEventDispatcher(); + new HookedServiceEventDispatcher(); HookedServiceEventDispatcher afterIndexed = - new HookedServiceEventDispatcher(); + new HookedServiceEventDispatcher(); HookedServiceEventDispatcher afterRead = new HookedServiceEventDispatcher(); HookedServiceEventDispatcher afterCreated = - new HookedServiceEventDispatcher(); + new HookedServiceEventDispatcher(); HookedServiceEventDispatcher afterModified = - new HookedServiceEventDispatcher(); + new HookedServiceEventDispatcher(); HookedServiceEventDispatcher afterUpdated = - new HookedServiceEventDispatcher(); + new HookedServiceEventDispatcher(); HookedServiceEventDispatcher afterRemoved = - new HookedServiceEventDispatcher(); + new HookedServiceEventDispatcher(); - HookedService(Service this.inner) : super() {} + HookedService(Service this.inner) { + // Clone all routes, including middleware + routes..clear()..addAll(inner.routes); + } @override Future index([Map params]) async { diff --git a/test/routing.dart b/test/routing.dart index e40fe288..e5c004b7 100644 --- a/test/routing.dart +++ b/test/routing.dart @@ -9,6 +9,14 @@ testMiddlewareMetadata(RequestContext req, ResponseContext res) async { return "This should not be shown."; } +class QueryService extends Service { + @override + @Middleware(const ['intercept_service', 'interceptor']) + read(id, [Map params]) { + return params; + } +} + main() { group('routing', () { Angel angel; @@ -22,10 +30,16 @@ main() { nested = new Angel(); todos = new Angel(); - angel.registerMiddleware('interceptor', (req, res) async { - res.write('Middleware'); - return false; - }); + angel + ..registerMiddleware('interceptor', (req, res) async { + res.write('Middleware'); + return false; + }) + ..registerMiddleware('intercept_service', + (RequestContext req, res) async { + print("Intercepting a service!"); + return true; + }); todos.get('/action/:action', (req, res) => res.json(req.params)); nested.post('/ted/:route', (req, res) => res.json(req.params)); @@ -37,12 +51,25 @@ main() { angel.post('/lambda', (req, res) => req.body); angel.use('/nes', nested); angel.use('/todos/:id', todos); - angel.get('/greet/:name', (RequestContext req, res) async => "Hello ${req.params['name']}").as('Named routes'); + angel + .get('/greet/:name', + (RequestContext req, res) async => "Hello ${req.params['name']}") + .as('Named routes'); angel.get('/named', (req, ResponseContext res) async { res.redirectTo('Named routes', {'name': 'tests'}); }); + angel.get('/log', (RequestContext req, res) async { + print("Query: ${req.query}"); + return "Logged"; + }); + angel.use('/query', new QueryService()); angel.get('*', 'MJ'); + print("DUMPING ROUTES: "); + for (Route route in angel.routes) { + print("${route.method} ${route.path} - ${route.handlers}"); + } + client = new http.Client(); await angel.startServer(InternetAddress.LOOPBACK_IP_V4, 0); url = "http://${angel.httpServer.address.host}:${angel.httpServer.port}"; @@ -97,8 +124,8 @@ main() { test('Can serialize function result as JSON', () async { Map headers = {'Content-Type': 'application/json'}; String postData = god.serialize({'it': 'works'}); - var response = await client.post( - "$url/lambda", headers: headers, body: postData); + var response = + await client.post("$url/lambda", headers: headers, body: postData); expect(god.deserialize(response.body)['it'], equals('works')); }); @@ -119,5 +146,16 @@ main() { print(response.body); expect(god.deserialize(response.body), equals('Hello tests')); }); + + test('Match routes, even with query params', () async { + var response = + await client.get("$url/log?foo=bar&bar=baz&baz.foo=bar&baz.bar=foo"); + print(response.body); + expect(god.deserialize(response.body), equals('Logged')); + + response = await client.get("$url/query/foo?bar=baz"); + print(response.body); + expect(response.body, equals("Middleware")); + }); }); -} \ No newline at end of file +}