Worked out some kinks in routing and hooked services. Services can use middleware.

This commit is contained in:
thosakwe 2016-06-23 15:05:55 -04:00
parent 80c6118544
commit 897a09d359
5 changed files with 98 additions and 33 deletions

View file

@ -73,7 +73,7 @@ class RequestContext extends Extensible {
context.contentType = request.headers.contentType; context.contentType = request.headers.contentType;
context.remoteAddress = request.connectionInfo.remoteAddress; context.remoteAddress = request.connectionInfo.remoteAddress;
context.params = parameters; 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.route = sourceRoute;
context.session = request.session; context.session = request.session;
context.underlyingRequest = request; context.underlyingRequest = request;

View file

@ -52,7 +52,7 @@ class Angel extends Routable {
server.listen((HttpRequest request) async { server.listen((HttpRequest request) async {
String req_url = 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 = '/'; if (req_url.isEmpty) req_url = '/';
RequestContext req = await RequestContext.from(request, {}, this, null); RequestContext req = await RequestContext.from(request, {}, this, null);
ResponseContext res = await ResponseContext.from(request.response, this); ResponseContext res = await ResponseContext.from(request.response, this);
@ -95,7 +95,7 @@ class Angel extends Routable {
if (!canContinue) break; if (!canContinue) break;
if (route.matcher.hasMatch(req_url) && if (route.matcher.hasMatch(req_url) &&
(request.method == route.method || route.method == '*')) { (request.method == route.method || route.method == '*')) {
req.params = route.parseParameters(request.uri.toString()); req.params = route.parseParameters(req_url);
req.route = route; req.route = route;
for (var handler in route.handlers) { for (var handler in route.handlers) {

View file

@ -60,22 +60,46 @@ class Service extends Routable {
Service() : super() { Service() : super() {
Map restProvider = {'provider': Providers.REST}; Map restProvider = {'provider': Providers.REST};
Middleware indexMiddleware = _getAnnotation(this.index, Middleware);
get('/', (req, res) async { get('/', (req, res) async {
return await this.index(mergeMap([req.query, restProvider])); 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 => Middleware readMiddleware = _getAnnotation(this.read, Middleware);
await this.read(req.params['id'], mergeMap([req.query, restProvider])));
patch('/:id', (req, res) async => await this.modify( get(
req.params['id'], req.body, restProvider)); '/: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( Middleware modifyMiddleware = _getAnnotation(this.modify, Middleware);
req.params['id'], req.body, restProvider)); 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( Middleware updateMiddleware = _getAnnotation(this.update, Middleware);
req.params['id'], mergeMap([req.query, restProvider]))); 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);
} }
} }

View file

@ -6,29 +6,32 @@ class HookedService extends Service {
final Service inner; final Service inner;
HookedServiceEventDispatcher beforeIndexed = HookedServiceEventDispatcher beforeIndexed =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeRead = new HookedServiceEventDispatcher(); HookedServiceEventDispatcher beforeRead = new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeCreated = HookedServiceEventDispatcher beforeCreated =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeModified = HookedServiceEventDispatcher beforeModified =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeUpdated = HookedServiceEventDispatcher beforeUpdated =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeRemoved = HookedServiceEventDispatcher beforeRemoved =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterIndexed = HookedServiceEventDispatcher afterIndexed =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterRead = new HookedServiceEventDispatcher(); HookedServiceEventDispatcher afterRead = new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterCreated = HookedServiceEventDispatcher afterCreated =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterModified = HookedServiceEventDispatcher afterModified =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterUpdated = HookedServiceEventDispatcher afterUpdated =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterRemoved = 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 @override
Future<List> index([Map params]) async { Future<List> index([Map params]) async {

View file

@ -9,6 +9,14 @@ testMiddlewareMetadata(RequestContext req, ResponseContext res) async {
return "This should not be shown."; return "This should not be shown.";
} }
class QueryService extends Service {
@override
@Middleware(const ['intercept_service', 'interceptor'])
read(id, [Map params]) {
return params;
}
}
main() { main() {
group('routing', () { group('routing', () {
Angel angel; Angel angel;
@ -22,10 +30,16 @@ main() {
nested = new Angel(); nested = new Angel();
todos = new Angel(); todos = new Angel();
angel.registerMiddleware('interceptor', (req, res) async { angel
res.write('Middleware'); ..registerMiddleware('interceptor', (req, res) async {
return false; 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)); todos.get('/action/:action', (req, res) => res.json(req.params));
nested.post('/ted/:route', (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.post('/lambda', (req, res) => req.body);
angel.use('/nes', nested); angel.use('/nes', nested);
angel.use('/todos/:id', todos); 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 { angel.get('/named', (req, ResponseContext res) async {
res.redirectTo('Named routes', {'name': 'tests'}); 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'); angel.get('*', 'MJ');
print("DUMPING ROUTES: ");
for (Route route in angel.routes) {
print("${route.method} ${route.path} - ${route.handlers}");
}
client = new http.Client(); client = new http.Client();
await angel.startServer(InternetAddress.LOOPBACK_IP_V4, 0); await angel.startServer(InternetAddress.LOOPBACK_IP_V4, 0);
url = "http://${angel.httpServer.address.host}:${angel.httpServer.port}"; url = "http://${angel.httpServer.address.host}:${angel.httpServer.port}";
@ -97,8 +124,8 @@ main() {
test('Can serialize function result as JSON', () async { test('Can serialize function result as JSON', () async {
Map headers = {'Content-Type': 'application/json'}; Map headers = {'Content-Type': 'application/json'};
String postData = god.serialize({'it': 'works'}); String postData = god.serialize({'it': 'works'});
var response = await client.post( var response =
"$url/lambda", headers: headers, body: postData); await client.post("$url/lambda", headers: headers, body: postData);
expect(god.deserialize(response.body)['it'], equals('works')); expect(god.deserialize(response.body)['it'], equals('works'));
}); });
@ -119,5 +146,16 @@ main() {
print(response.body); print(response.body);
expect(god.deserialize(response.body), equals('Hello tests')); 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"));
});
}); });
} }