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.remoteAddress = request.connectionInfo.remoteAddress;
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.session = request.session;
context.underlyingRequest = request;

View file

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

View file

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

@ -28,7 +28,10 @@ class HookedService extends Service {
HookedServiceEventDispatcher afterRemoved =
new HookedServiceEventDispatcher();
HookedService(Service this.inner) : super() {}
HookedService(Service this.inner) {
// Clone all routes, including middleware
routes..clear()..addAll(inner.routes);
}
@override
Future<List> index([Map params]) async {

View file

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