-
Notifications
You must be signed in to change notification settings - Fork 129
Open
Labels
Description
Improvements to Shelf Router
Based on this comment I decided to play around and implement a router based on radix tree similar to how echo does it
From there, I went down into the rabbit hole and decided to add more features like grouping and middlewares
The final result (in use) looks like this
void main() async {
final router = Router.builder()
..use(logRequests())
..use((Handler handler) => (Request request) {
print('Global middleware: ${request.method} ${request.requestedUri}');
return handler(request);
})
..get('/', (Request req) => Response.ok('Hello from the root route'))
..get('/hello', (Request req) => Response.ok('Hello World!'))
..get('/user/<name>', (Request req, String name) => Response.ok('Hello, $name!'))
..post('/data', (Request req) async {
final payload = await req.readAsString();
return Response.ok('Data received: $payload');
});
router.group('/group1')
..get('/info', (Request req) => Response.ok('Group1 Info'))
..get('/items', (Request req) => Response.ok('Group1 Items list'))
..put('/item/<id>', (Request req, String id) => Response.ok('Updated item with id $id'))
..delete('/item/<id>', (Request req, String id) => Response.ok('Deleted item with id $id'));
router.group('/group2')
..use((Handler handler) => (Request req) {
print('Group2 middleware 1: ${req.method} ${req.requestedUri}');
return handler(req);
})
..get('/status', (Request req) => Response.ok('Status OK'))
..use((Handler handler) => (Request req) {
print('Group2 middleware 2: ${req.method} ${req.requestedUri}');
return handler(req);
})
..get('/metrics', (Request req) => Response.ok('Metrics: 123'));
final server = await serve(router.call, 'localhost', 8080);
print('Server listening on port ${server.port}');
}
The tree created from this router looks something like this
Middlewares will be inherited down the tree
flowchart TD
%% Radix Tree Root and HTTP Verb Layer
R0["Root"]
R0 --> GM(["Global Middleware"])
GM --> GET["GET"]
GM --> POST["POST"]
GM --> PUT["PUT"]
GM --> DELETE["DELETE"]
%% GET Method Routes
GET --> R1["/"]
GET --> R2["/hello"]
GET --> R3["/user"]
R3 --> R4["/<name>"]
%% Group1 Routes (prefix: /group1)
GET --> G1["/group1"]
G1 --> G1a["/info"]
G1 --> G1b["/items"]
%% Group2 Routes (prefix: /group2)
GET --> G2["/group2"]
G2 --> G2M1(["Middleware 1"])
G2M1 --> G2a["/status"]
G2M1 --> G2M2(["Middleware 2"])
G2M2 --> G2b["/metrics"]
%% POST Method Routes
POST --> P1["/data"]
%% PUT Method Routes (Group1 Route: /group1/item/<id>)
PUT --> G1_put["/group1"]
G1_put --> G1_put_item["/item"]
G1_put_item --> G1_put_id["/<id>"]
%% DELETE Method Routes (Group1 Route: /group1/item/<id>)
DELETE --> G1_del["/group1"]
G1_del --> G1_del_item["/item"]
G1_del_item --> G1_del_id["/<id>"]
I think this kind of router would add value to the ecosystem. There are third party alternatives that achieve something similar, but I would prefer to have a native solution rather than using/creating an external library
Would you guys be open to a PR?
devkaio and bivens-dev