Router: allow to mount a Handler (#86)

* Router: allow to mount a handler


And make Router to be a Handler

* Deprecate the handler getter of Router

* Add a changelog entry and bump version
diff --git a/pkgs/shelf_router/CHANGELOG.md b/pkgs/shelf_router/CHANGELOG.md
index f3e0569..0c63df2 100644
--- a/pkgs/shelf_router/CHANGELOG.md
+++ b/pkgs/shelf_router/CHANGELOG.md
@@ -1,3 +1,9 @@
+## v0.7.4
+
+ * Update `Router.mount` parameter to accept a `Handler`.
+ * Make `Router` to be considered a `Handler`.
+ * Deprecate the `Router.handler` getter.
+
 ## v0.7.3
 
  * Added `@sealed` annotation to `Router` and `Route`.
diff --git a/pkgs/shelf_router/example/main.dart b/pkgs/shelf_router/example/main.dart
index e95344d..ebd7dfd 100644
--- a/pkgs/shelf_router/example/main.dart
+++ b/pkgs/shelf_router/example/main.dart
@@ -52,7 +52,7 @@
       return Response.notFound('Page not found');
     });
 
-    return router.handler;
+    return router;
   }
 }
 
diff --git a/pkgs/shelf_router/lib/src/router.dart b/pkgs/shelf_router/lib/src/router.dart
index a3102cd..ba086d3 100644
--- a/pkgs/shelf_router/lib/src/router.dart
+++ b/pkgs/shelf_router/lib/src/router.dart
@@ -115,18 +115,17 @@
     _routes.add(RouterEntry('ALL', route, handler));
   }
 
-  /// Mount a router below a prefix.
+  /// Mount a handler below a prefix.
   ///
   /// In this case prefix may not contain any parameters, nor
-  void mount(String prefix, Router router) {
+  void mount(String prefix, Handler handler) {
     ArgumentError.checkNotNull(prefix, 'prefix');
-    ArgumentError.checkNotNull(router, 'router');
+    ArgumentError.checkNotNull(handler, 'handler');
     if (!prefix.startsWith('/') || !prefix.endsWith('/')) {
       throw ArgumentError.value(
           prefix, 'prefix', 'must start and end with a slash');
     }
 
-    final handler = router.handler;
     // first slash is always in request.handlerPath
     final path = prefix.substring(1);
     all(prefix + '<path|[^]*>', (Request request) {
@@ -135,24 +134,28 @@
   }
 
   /// Get a [Handler] that will route incoming requests to registered handlers.
-  Handler get handler {
+  @Deprecated('The Router class is a Handler on its own')
+  Handler get handler => call;
+
+  /// Route incoming requests to registered handlers.
+  ///
+  /// This method allows a Router instance to be a [Handler].
+  Future<Response> call(Request request) async {
     // Note: this is a great place to optimize the implementation by building
     //       a trie for faster matching... left as an exercise for the reader :)
-    return (Request request) async {
-      for (var route in _routes) {
-        if (route.verb != request.method.toUpperCase() && route.verb != 'ALL') {
-          continue;
-        }
-        var params = route.match('/' + request.url.path);
-        if (params != null) {
-          var res = await route.invoke(request, params);
-          if (res != null) {
-            return res;
-          }
+    for (var route in _routes) {
+      if (route.verb != request.method.toUpperCase() && route.verb != 'ALL') {
+        continue;
+      }
+      var params = route.match('/' + request.url.path);
+      if (params != null) {
+        var res = await route.invoke(request, params);
+        if (res != null) {
+          return res;
         }
       }
-      return null;
-    };
+    }
+    return null;
   }
 
   // Handlers for all methods
diff --git a/pkgs/shelf_router/pubspec.yaml b/pkgs/shelf_router/pubspec.yaml
index c0befeb..394d5c7 100644
--- a/pkgs/shelf_router/pubspec.yaml
+++ b/pkgs/shelf_router/pubspec.yaml
@@ -1,5 +1,5 @@
 name: shelf_router
-version: 0.7.3
+version: 0.7.4
 description: |
   A convinent request router for the shelf web-framework, with support for
   URL-parameters, nested routers and routers generated from source annotations.
diff --git a/pkgs/shelf_router/test/router_test.dart b/pkgs/shelf_router/test/router_test.dart
index 5eeae1b..3f33d91 100644
--- a/pkgs/shelf_router/test/router_test.dart
+++ b/pkgs/shelf_router/test/router_test.dart
@@ -60,7 +60,7 @@
       return Response.ok('not-found');
     });
 
-    server.mount(app.handler);
+    server.mount(app);
 
     expect(await get('/sync-hello'), 'hello-world');
     expect(await get('/async-hello'), 'hello-world');
@@ -80,7 +80,7 @@
       return Response.ok('$user / $group');
     });
 
-    server.mount(app.handler);
+    server.mount(app);
 
     expect(await get('/user/jonasfj/groups/42'), 'jonasfj / 42');
   });
@@ -93,7 +93,7 @@
       return Response.ok('$user / $group');
     });
 
-    server.mount(app.handler);
+    server.mount(app);
 
     expect(await get('/user/jonasfj/groups/42'), 'jonasfj / 42');
   });
@@ -115,10 +115,37 @@
       return Response.notFound('catch-all-handler');
     });
 
-    server.mount(app.handler);
+    server.mount(app);
 
     expect(await get('/hello'), 'hello-world');
     expect(await get('/api/user/jonasfj/info'), 'Hello jonasfj');
     expect(get('/api/user/jonasfj/info-wrong'), throwsA(anything));
   });
+
+  test('mount(Handler) with middleware', () async {
+    var api = Router();
+    api.get('/hello', (Request request) {
+      return Response.ok('Hello');
+    });
+
+    final middleware = createMiddleware(
+      requestHandler: (request) {
+        if (request.url.queryParameters.containsKey('ok')) {
+          return Response.ok('middleware');
+        }
+        return null;
+      },
+    );
+
+    var app = Router();
+    app.mount(
+      '/api/',
+      Pipeline().addMiddleware(middleware).addHandler(api),
+    );
+
+    server.mount(app);
+
+    expect(await get('/api/hello'), 'Hello');
+    expect(await get('/api/hello?ok'), 'middleware');
+  });
 }