Skip to content

Commit 73883e7

Browse files
committed
feat: support for more routing patterns with tests
1 parent 76d48d4 commit 73883e7

File tree

6 files changed

+61
-19
lines changed

6 files changed

+61
-19
lines changed

bin/run.dart

+5-12
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void main(List<String> arguments) async {
2929

3030
router.get<Stream<String>>('/', (event) {
3131
setResponseHeader(event, HttpHeaders.contentTypeHeader,
32-
value: 'text/event-stream text/html');
32+
value: 'text/event-stream');
3333

3434
setResponseHeader(event, HttpHeaders.cacheControlHeader,
3535
value:
@@ -47,24 +47,17 @@ void main(List<String> arguments) async {
4747
return countStream(8);
4848
});
4949

50-
router.get("/hi/:id", (event) {
51-
throw Exception('Yo');
52-
// return 'Hey ${event.params["id"]}';
53-
});
54-
55-
router.post("/vamos", (event) async {
50+
router.post("/vamos/:id/**", (event) async {
5651
var body = await readRequestBody(event);
5752
var header = getHeader(event, HttpHeaders.userAgentHeader);
5853
var query = getQueryParams(event);
5954
setResponseHeader(event, HttpHeaders.contentTypeHeader,
6055
value: 'application/json');
61-
return [header, body, query];
56+
return [header, body, query, event.params];
6257
});
6358

64-
router.get<Future<int>>('/int', (event) async {
65-
await Future.delayed(Duration(seconds: 4));
66-
var res = await Future.value(23994);
67-
return res;
59+
router.get<Future<dynamic>>('/int', (event) async {
60+
return Future.error(Exception('Hula ballo'));
6861
});
6962

7063
router.get("/vamos", (event) {

lib/src/event.dart

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:async';
12
import 'dart:convert';
23
import 'dart:core';
34
import 'dart:io';
@@ -95,20 +96,26 @@ class H4Event {
9596
///
9697
/// If the [handlerResult] is `null`, the response will be closed without writing any content.
9798
/// The [handled] flag is set to `true` after the response is sent.
98-
void respond(dynamic handlerResult) {
99+
void respond(dynamic handlerResult) async {
99100
if (_handled) {
100101
return;
101102
}
102103

103104
if (handlerResult is Stream) {
104105
_request.response.persistentConnection = true;
106+
107+
final controller = StreamController<dynamic>.broadcast();
108+
105109
handlerResult.listen((value) {
106-
print(value);
107110
_request.response.write('data: ${value.toString()} \n');
111+
_request.response.flush();
108112
}, onDone: () {
109-
print('stram finished');
113+
_request.response.write('data: [DONE]\n');
110114
_shutDown();
115+
controller.close();
111116
});
117+
118+
await controller.stream.drain();
112119
return;
113120
}
114121

lib/src/index.dart

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Function(HttpRequest) defineEventHandler(
1616
Map<String, String>? params,
1717
}) {
1818
return (HttpRequest request) {
19+
request.response.headers.contentType = null;
1920
// Create an event with the incoming request.
2021
var event = H4Event(request);
2122

lib/src/router.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ class H4Router {
5050
/// - A normalized request method string [GET, POST, PUT, DELETE, PATCH]
5151
Map<String, EventHandler?>? lookup(path) {
5252
var pathChunks = extractPieces(path);
53+
5354
var result = routes.search(pathChunks);
5455

5556
result ??= routes.matchParamRoute(pathChunks);
5657

57-
result ??= routes.matchWildCardRoute(extractPieces(path));
58+
result ??= routes.matchWildCardRoute(pathChunks);
5859

5960
return result;
6061
}

lib/src/trie.dart

+8-3
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,15 @@ class Trie {
7272
TrieNode? currNode = root;
7373

7474
for (String pathPiece in pathPieces) {
75+
int index = pathPieces.indexOf(pathPiece);
7576
if (currNode?.children[pathPiece] == null) {
7677
currNode?.children.forEach((key, value) {
77-
if ((key.startsWith(":") || key.startsWith("*")) &&
78-
value.handlers.isNotEmpty) {
78+
if ((key.startsWith(":") || key.startsWith("*")) && value.isLeaf) {
7979
// Do not behave like a wildcard. Only match if the param route is an exact match.
8080
if (pathPieces.lastOrNull == pathPiece) {
81-
laHandler = value.handlers;
81+
if (index == pathPieces.length - 1) {
82+
laHandler = value.handlers;
83+
}
8284
} else {
8385
// Handle weird edge case where a handler with id as a leaf is defined in route trie
8486
var result = deepTraverse(value.children);
@@ -141,6 +143,9 @@ class Trie {
141143
currNode?.children.forEach((key, value) {
142144
if (key.startsWith("**") && value.isLeaf) {
143145
laHandler = value.handlers;
146+
} else {
147+
var result = deepTraverse(value.children);
148+
laHandler = result["handlers"];
144149
}
145150
});
146151
}

test/h4_test.dart

+35
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,39 @@ void main() {
8383
final response = await dio.get('/async');
8484
expect(response.data, '6700');
8585
});
86+
87+
test('Handles single dynamic routes', () async {
88+
router.get('/user/:id', (event) => event.params['id']);
89+
90+
final response = await dio.get('/user/xyz_abc_123');
91+
expect(response.data, 'xyz_abc_123');
92+
});
93+
94+
test('Handles match-all wildcard routes', () async {
95+
router.get('/user/**', (event) => "Welcome to H4!");
96+
97+
final req1 = dio.get('/user/fun');
98+
final req2 = dio.get('/user/fun/me');
99+
final req3 = dio.get('/user/fun/me/you');
100+
101+
final responses = await Future.wait([req1, req2, req3]);
102+
103+
for (final response in responses) {
104+
expect(response.data, "Welcome to H4!");
105+
}
106+
});
107+
108+
test('Handles paramaterized match-all requests', () async {
109+
router.get('/donut/:id/**', (event) => "Welcome to H4!");
110+
111+
final req1 = dio.get('/donut/user/fun');
112+
final req2 = dio.get('/donut/user/fun/me');
113+
final req3 = dio.get('/donut/user/fun/me/you');
114+
115+
final responses = await Future.wait([req1, req2, req3]);
116+
117+
for (final response in responses) {
118+
expect(response.data, "Welcome to H4!");
119+
}
120+
});
86121
}

0 commit comments

Comments
 (0)