Make default handler customizable
diff --git a/pkgs/shelf_router/CHANGELOG.md b/pkgs/shelf_router/CHANGELOG.md
index 49ab39f..ee8b207 100644
--- a/pkgs/shelf_router/CHANGELOG.md
+++ b/pkgs/shelf_router/CHANGELOG.md
@@ -1,6 +1,10 @@
## v0.8.0-nullsafety.0
* Migrate package to null-safety
+ * Since handlers are not allowed to return `null` in `shelf` 1.0.0, a router
+ will return a default 404 response instead.
+ This behavior can be overridden with the `notFoundHandler` constructor
+ parameter.
## v0.7.4
diff --git a/pkgs/shelf_router/lib/src/router.dart b/pkgs/shelf_router/lib/src/router.dart
index c0012d2..51f96fd 100644
--- a/pkgs/shelf_router/lib/src/router.dart
+++ b/pkgs/shelf_router/lib/src/router.dart
@@ -26,7 +26,7 @@
if (!(p is Map<String, String>)) {
throw Exception('no such parameter $name');
}
- final value = (p)[name];
+ final value = p[name];
if (value == null) {
throw Exception('no such parameter $name');
}
@@ -78,13 +78,21 @@
/// ```
///
/// If multiple routes match the same request, the handler for the first
-/// route is called. If the handler returns `null` the next matching handler
-/// will be attempted.
-///
-///
+/// route is called.
+/// If no route matches a request, a [Response.notFound] will be returned
+/// instead. The default matcher can be overridden with the `notFoundHandler`
+/// constructor parameter.
@sealed
class Router {
final List<RouterEntry> _routes = [];
+ final Handler _notFoundHandler;
+
+ /// Creates a new [Router] routing requests to handlers.
+ ///
+ /// The [notFoundHandler] will be invoked for requests where no matching route
+ /// was found. By default, a simple [Response.notFound] will be used instead.
+ Router({Handler notFoundHandler = _defaultNotFound})
+ : _notFoundHandler = notFoundHandler;
/// Add [handler] for [verb] requests to [route].
///
@@ -149,7 +157,7 @@
return await route.invoke(request, params);
}
}
- return Response.notFound('Not Found');
+ return _notFoundHandler(request);
}
// Handlers for all methods
@@ -185,4 +193,8 @@
/// Handle `PATCH` request to [route] using [handler].
void patch(String route, Function handler) => add('PATCH', route, handler);
+
+ static Response _defaultNotFound(Request request) {
+ return Response.notFound('Not Found');
+ }
}
diff --git a/pkgs/shelf_router/test/router_test.dart b/pkgs/shelf_router/test/router_test.dart
index e5997dd..01ca321 100644
--- a/pkgs/shelf_router/test/router_test.dart
+++ b/pkgs/shelf_router/test/router_test.dart
@@ -147,4 +147,22 @@
expect(await get('/api/hello'), 'Hello');
expect(await get('/api/hello?ok'), 'middleware');
});
+
+ test('responds with 404 if no handler matches', () {
+ var api = Router()..get('/hello', (request) => Response.ok('Hello'));
+ server.mount(api);
+
+ expect(
+ get('/hi'),
+ throwsA(isA<http.ClientException>()
+ .having((e) => e.message, 'message', contains('404: Not Found.'))));
+ });
+
+ test('can invoke custom handler if no route matches', () {
+ var api = Router(notFoundHandler: (req) => Response.ok('Not found, but ok'))
+ ..get('/hello', (request) => Response.ok('Hello'));
+ server.mount(api);
+
+ expect(get('/hi'), completion('Not found, but ok'));
+ });
}