Controllers should be able to handle errors themselves

This commit is contained in:
regiostech 2016-07-04 14:06:31 -04:00
parent 1a7d831a36
commit 76d26ea9c5
4 changed files with 90 additions and 84 deletions

View file

@ -52,33 +52,29 @@ class Controller {
ResponseContext res) async { ResponseContext res) async {
List args = []; List args = [];
try { // Load parameters, and execute
// Load parameters, and execute for (int i = 0; i < methodMirror.parameters.length; i++) {
for (int i = 0; i < methodMirror.parameters.length; i++) { ParameterMirror parameter = methodMirror.parameters[i];
ParameterMirror parameter = methodMirror.parameters[i]; if (parameter.type.reflectedType == RequestContext)
if (parameter.type.reflectedType == RequestContext) args.add(req);
args.add(req); else if (parameter.type.reflectedType == ResponseContext)
else if (parameter.type.reflectedType == ResponseContext) args.add(res);
args.add(res); else {
else { String name = MirrorSystem.getName(parameter.simpleName);
String name = MirrorSystem.getName(parameter.simpleName); var arg = req.params[name];
var arg = req.params[name];
if (arg == null && if (arg == null &&
!exposeMirror.reflectee.allowNull.contain(name)) { !exposeMirror.reflectee.allowNull.contain(name)) {
throw new AngelHttpException.BadRequest(); throw new AngelHttpException.BadRequest();
}
args.add(arg);
} }
}
return await instanceMirror args.add(arg);
.invoke(key, args) }
.reflectee;
} catch (e) {
throw new AngelHttpException(e);
} }
return await instanceMirror
.invoke(key, args)
.reflectee;
}; };
Route route = new Route( Route route = new Route(
exposeMirror.reflectee.method, exposeMirror.reflectee.method,

View file

@ -83,7 +83,7 @@ class ResponseContext extends Extensible {
<body> <body>
<h1>Currently redirecting you...</h1> <h1>Currently redirecting you...</h1>
<br /> <br />
Click <a href="$url"></a> if you are not automatically redirected... Click <a href="$url">here</a> if you are not automatically redirected...
<script> <script>
window.location = "$url"; window.location = "$url";
</script> </script>

View file

@ -12,6 +12,12 @@ typedef Future AngelConfigurer(Angel app);
/// A powerful real-time/REST/MVC server class. /// A powerful real-time/REST/MVC server class.
class Angel extends Routable { class Angel extends Routable {
var _beforeProcessed = new StreamController<HttpRequest>();
var _afterProcessed = new StreamController<HttpRequest>();
Stream<HttpRequest> get beforeProcessed => _beforeProcessed.stream;
Stream<HttpRequest> get afterProcessed => _afterProcessed.stream;
ServerGenerator _serverGenerator = ServerGenerator _serverGenerator =
(address, port) async => await HttpServer.bind(address, port); (address, port) async => await HttpServer.bind(address, port);
@ -50,69 +56,72 @@ class Angel extends Routable {
await _serverGenerator(address ?? InternetAddress.LOOPBACK_IP_V4, port); await _serverGenerator(address ?? InternetAddress.LOOPBACK_IP_V4, port);
this.httpServer = server; this.httpServer = server;
server.listen((HttpRequest request) async { server.listen(handleRequest);
String req_url =
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);
bool canContinue = true;
var execHandler = (handler, req) async {
if (canContinue) {
canContinue = await new Future.sync(() async {
return _applyHandler(handler, req, res);
}).catchError((e, [StackTrace stackTrace]) async {
if (e is AngelHttpException) {
// Special handling for AngelHttpExceptions :)
try {
res.status(e.statusCode);
String accept = request.headers.value(HttpHeaders.ACCEPT);
if (accept == "*/*" ||
accept.contains("application/json") ||
accept.contains("application/javascript")) {
res.json(e.toMap());
} else {
await _errorHandler(e, req, res);
}
_finalizeResponse(request, res);
} catch (_) {}
}
_onError(e, stackTrace);
canContinue = false;
return false;
});
} else
return false;
};
for (var handler in before) {
await execHandler(handler, req);
}
for (Route route in routes) {
if (!canContinue) break;
if (route.matcher.hasMatch(req_url) &&
(request.method == route.method || route.method == '*')) {
req.params = route.parseParameters(req_url);
req.route = route;
for (var handler in route.handlers) {
await execHandler(handler, req);
}
}
}
for (var handler in after) {
await execHandler(handler, req);
}
_finalizeResponse(request, res);
});
return server; return server;
} }
Future handleRequest(HttpRequest request) async {
_beforeProcessed.add(request);
String req_url =
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);
bool canContinue = true;
var execHandler = (handler, req) async {
if (canContinue) {
canContinue = await new Future.sync(() async {
return _applyHandler(handler, req, res);
}).catchError((e, [StackTrace stackTrace]) async {
if (e is AngelHttpException) {
// Special handling for AngelHttpExceptions :)
try {
res.status(e.statusCode);
String accept = request.headers.value(HttpHeaders.ACCEPT);
if (accept == "*/*" ||
accept.contains("application/json") ||
accept.contains("application/javascript")) {
res.json(e.toMap());
} else {
await _errorHandler(e, req, res);
}
_finalizeResponse(request, res);
} catch (_) {}
}
_onError(e, stackTrace);
canContinue = false;
return false;
});
} else
return false;
};
for (var handler in before) {
await execHandler(handler, req);
}
for (Route route in routes) {
if (!canContinue) break;
if (route.matcher.hasMatch(req_url) &&
(request.method == route.method || route.method == '*')) {
req.params = route.parseParameters(req_url);
req.route = route;
for (var handler in route.handlers) {
await execHandler(handler, req);
}
}
}
for (var handler in after) {
await execHandler(handler, req);
}
_finalizeResponse(request, res);
}
Future<bool> _applyHandler( Future<bool> _applyHandler(
handler, RequestContext req, ResponseContext res) async { handler, RequestContext req, ResponseContext res) async {
if (handler is RequestMiddleware) { if (handler is RequestMiddleware) {
@ -162,6 +171,7 @@ class Angel extends Routable {
if (!res.willCloseItself) { if (!res.willCloseItself) {
res.responseData.forEach((blob) => request.response.add(blob)); res.responseData.forEach((blob) => request.response.add(blob));
await request.response.close(); await request.response.close();
_afterProcessed.add(request);
} }
} catch (e) { } catch (e) {
// Remember: This fails silently // Remember: This fails silently

View file

@ -1,5 +1,5 @@
name: angel_framework name: angel_framework
version: 1.0.0-dev.8 version: 1.0.0-dev.13
description: Core libraries for the Angel framework. description: Core libraries for the Angel framework.
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/angel_framework homepage: https://github.com/angel-dart/angel_framework