Force all handlers to (req, res) { ... }

This commit is contained in:
Tobe O 2018-08-20 16:21:06 -04:00
parent b9127251a6
commit 3c37747f07
12 changed files with 74 additions and 61 deletions

View file

@ -34,4 +34,9 @@ as well as `query`.
* Removed a dependency on `package:pool`, which also meant removing `AngelHttp.throttle`.
* Remove the `RequestMiddleware` typedef; from now on, one should use `ResponseContext.end`
exclusively to close responses.
* `waterfall` will now only accept `RequestHandler`.
* `waterfall` will now only accept `RequestHandler`.
* `Routable`, and all of its subclasses, now extend `Router<RequestHandler>`, and therefore only
take routes in the form of `FutureOr myFunc(RequestContext, ResponseContext res)`.
* `@Middleware` now takes an `Iterable` of `RequestHandler`s.
* `@Expose.path` now *must* be a `String`, not just any `Pattern`.
* `@Expose.middleware` now takes `Iterable<RequestHandler>`, instead of just `List`.

View file

@ -32,15 +32,16 @@ serverMain(_) async {
var app = new Angel(reflector: MirrorsReflector());
var http = new AngelHttp.custom(app, startShared); // Run a cluster
app.get('/', {
"foo": "bar",
"one": [2, "three"],
"bar": {"baz": "quux"}
app.get('/', (req, res) {
res.serialize({
"foo": "bar",
"one": [2, "three"],
"bar": {"baz": "quux"}
});
});
// Performance tuning
app
..serializer = json.encode;
app..serializer = json.encode;
app.errorHandler = (e, req, res) {
print(e.message ?? e.error ?? e);

View file

@ -8,7 +8,7 @@ main() async {
'View generator invoked with name $name and data: $data';
// Index route. Returns JSON.
app.get('/', (ResponseContext res) => res.render('index', {'foo': 'bar'}));
app.get('/', (req, res) => res.render('index', {'foo': 'bar'}));
var http = new AngelHttp(app);
var server = await http.startServer('127.0.0.1', 3000);

View file

@ -4,6 +4,7 @@ import 'dart:async';
import '../util.dart';
import 'request_context.dart';
import 'response_context.dart';
import 'routable.dart';
import 'metadata.dart';
import 'service.dart';
@ -119,7 +120,7 @@ class HookedService extends Service {
applyListeners(inner.remove, afterRemoved, true);
}
List get bootstrappers => new List.from(super.bootstrappers)
List<RequestHandler> get bootstrappers => new List<RequestHandler>.from(super.bootstrappers)
..add((RequestContext req, ResponseContext res) {
req.serviceParams
..['__requestctx'] = req

View file

@ -1,12 +1,14 @@
library angel_framework.http.metadata;
import 'hooked_service.dart' show HookedServiceEventListener;
import 'package:angel_http_exception/angel_http_exception.dart';
import 'hooked_service.dart' show HookedServiceEventListener;
import 'request_context.dart';
import 'routable.dart';
/// Annotation to map middleware onto a handler.
class Middleware {
final List handlers;
final Iterable<RequestHandler> handlers;
const Middleware(this.handlers);
}
@ -22,8 +24,8 @@ class Hooks {
/// Exposes a [Controller] to the Internet.
class Expose {
final String method;
final Pattern path;
final List middleware;
final String path;
final Iterable<RequestHandler> middleware;
final String as;
final List<String> allowNull;
@ -91,7 +93,8 @@ class Parameter {
return req.headers.value(header) ?? defaultValue;
if (session?.isNotEmpty == true)
return req.session[session] ?? defaultValue;
if (query?.isNotEmpty == true) return req.uri.queryParameters[query] ?? defaultValue;
if (query?.isNotEmpty == true)
return req.uri.queryParameters[query] ?? defaultValue;
return defaultValue;
}
}

View file

@ -42,7 +42,7 @@ RequestHandler waterfall(Iterable<RequestHandler> handlers) {
}
/// A routable server that can handle dynamic requests.
class Routable extends Router {
class Routable extends Router<RequestHandler> {
final Map<Pattern, Service> _services = {};
final Map configuration = {};
@ -71,16 +71,17 @@ class Routable extends Router {
_services[path.toString().replaceAll(_straySlashes, '')];
@override
Route addRoute(String method, String path, Object handler,
{Iterable middleware: const []}) {
final List handlers = [];
Route<RequestHandler> addRoute(
String method, String path, RequestHandler handler,
{Iterable<RequestHandler> middleware: const <RequestHandler>[]}) {
final handlers = <RequestHandler>[];
// Merge @Middleware declaration, if any
Middleware middlewareDeclaration = getAnnotation(handler, Middleware);
if (middlewareDeclaration != null) {
handlers.addAll(middlewareDeclaration.handlers);
}
final List handlerSequence = [];
final handlerSequence = <RequestHandler>[];
handlerSequence.addAll(middleware ?? []);
handlerSequence.addAll(handlers);
@ -94,8 +95,8 @@ class Routable extends Router {
/// an [Angel] instance.
///
/// Returns either a [Route] or a [Service] (if one was mounted).
use(path, [Router router, String namespace = null]) {
Router _router = router;
use(path, [Router<RequestHandler> router, String namespace = null]) {
Router<RequestHandler> _router = router;
Service service;
// If we need to hook this service, do it here. It has to be first, or

View file

@ -162,8 +162,8 @@ class Angel extends Routable {
};
@override
Route addRoute(String method, Pattern path, Object handler,
{List middleware: const []}) {
Route addRoute(String method, String path, Object handler,
{Iterable middleware: const []}) {
if (_flattened != null) {
logger?.warning(
'WARNING: You added a route ($method $path) to the router, after it had been optimized.');

View file

@ -58,7 +58,7 @@ class Service extends Routable {
];
/// Handlers that must run to ensure this service's functionality.
List get bootstrappers => [];
List<RequestHandler> get bootstrappers => [];
/// The [Angel] app powering this service.
Angel app;
@ -150,8 +150,9 @@ class Service extends Routable {
_addRoutesInner(service ?? this, bootstrappers);
}
void _addRoutesInner(Service service, List handlers) {
Map restProvider = {'provider': Providers.rest};
void _addRoutesInner(Service service, Iterable<RequestHandler> handlerss) {
var restProvider = {'provider': Providers.rest};
var handlers = new List<RequestHandler>.from(handlerss);
// Add global middleware if declared on the instance itself
Middleware before = getAnnotation(service, Middleware);
@ -168,7 +169,7 @@ class Service extends Routable {
]));
});
},
middleware: []
middleware: <RequestHandler>[]
..addAll(handlers)
..addAll((indexMiddleware == null) ? [] : indexMiddleware.handlers));

View file

@ -60,7 +60,7 @@ class Controller {
}
void Function(Symbol, MethodMirror) _routeBuilder(
InstanceMirror instanceMirror, Routable routable, List handlers) {
InstanceMirror instanceMirror, Routable routable, Iterable<RequestHandler> handlers) {
return (Symbol methodName, MethodMirror method) {
if (method.isRegularMethod &&
methodName != #toString &&
@ -76,7 +76,7 @@ class Controller {
var reflectedMethod =
instanceMirror.getField(methodName).reflectee as Function;
var middleware = []..addAll(handlers)..addAll(exposeDecl.middleware);
var middleware = <RequestHandler>[]..addAll(handlers)..addAll(exposeDecl.middleware);
String name = exposeDecl.as?.isNotEmpty == true
? exposeDecl.as
: MirrorSystem.getName(methodName);

View file

@ -13,8 +13,8 @@ main() {
setUp(() async {
app = new Angel(reflector: MirrorsReflector())
..post('/foo', () => {'hello': 'world'})
..all('*', () => throw new AngelHttpException.notFound());
..post('/foo', (req, res) => res.serialize({'hello': 'world'}))
..all('*', (req, res) => throw new AngelHttpException.notFound());
client = new http.Client();
server = await new AngelHttp(app).startServer();

View file

@ -1,25 +1,37 @@
import 'dart:convert';
import 'dart:io';
import 'package:angel_container/mirrors.dart';
import 'package:angel_framework/angel_framework.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:io/ansi.dart';
import 'package:logging/logging.dart';
import 'package:test/test.dart';
import 'common.dart';
@Middleware(const ['interceptor'])
@Middleware([interceptor])
testMiddlewareMetadata(RequestContext req, ResponseContext res) async {
return "This should not be shown.";
}
@Middleware(const ['intercept_service'])
@Middleware([interceptService])
class QueryService extends Service {
@override
@Middleware(const ['interceptor'])
@Middleware([interceptor])
read(id, [Map params]) async => params;
}
void interceptor(RequestContext req, ResponseContext res) {
res
..write('Middleware')
..end();
}
void interceptService(RequestContext req, ResponseContext res) {
res.write("Service with ");
}
main() {
Angel app;
Angel nested;
@ -44,16 +56,6 @@ main() {
});
});
app.requestMiddleware
..['interceptor'] = (req, res) async {
res.write('Middleware');
return false;
}
..['intercept_service'] = (RequestContext req, res) async {
res.write("Service with ");
return true;
};
todos.get('/action/:action', (req, res) => res.json(req.params));
Route ted;
@ -67,8 +69,7 @@ main() {
app.use('/nes', nested);
app.get('/meta', testMiddlewareMetadata);
app.get('/intercepted', 'This should not be shown',
middleware: ['interceptor']);
app.get('/intercepted', 'This should not be shown', middleware: ['interceptor']);
app.get('/hello', 'world');
app.get('/name/:first/last/:last', (req, res) => req.params);
app.post('/lambda', (RequestContext req, res) => req.parseBody());
@ -90,16 +91,14 @@ main() {
app.use('/query', new QueryService());
RequestMiddleware write(String message) {
return (req, res) async {
RequestHandler write(String message) {
return (req, res) {
res.write(message);
return true;
};
}
app
.chain(write('a'))
.chain([write('b'), write('c')]).get('/chained', () => false);
app.chain([write('a')]).chain([write('b'), write('c')]).get(
'/chained', () => false);
app.use('MJ');
@ -179,7 +178,7 @@ main() {
});
test('Can name routes', () {
Route foo = app.get('/framework/:id', [])..name = 'frm';
Route foo = app.get('/framework/:id', null)..name = 'frm';
print('Foo: $foo');
String uri = foo.makeUri({'id': 'angel'});
print(uri);

View file

@ -1,12 +1,14 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io' show stderr;
import 'dart:io';
import 'package:angel_container/mirrors.dart';
import 'package:angel_framework/angel_framework.dart';
import 'dart:convert';
import 'dart:io';
import 'package:logging/logging.dart';
import 'package:mock_request/mock_request.dart';
import 'package:test/test.dart';
import 'encoders_buffer_test.dart' show encodingTests;
main() {
@ -30,18 +32,18 @@ main() {
},
);
app.get('/hello', (ResponseContext res) {
app.get('/hello', (req, res) {
new Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits]).pipe(res);
});
app.get('/write', (res) async {
app.get('/write', (req, res) async {
await res.addStream(
new Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits]));
res.write('bye');
await res.close();
});
app.get('/multiple', (res) async {
app.get('/multiple', (req, res) async {
await res.addStream(
new Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits]));
await res
@ -49,7 +51,7 @@ main() {
await res.close();
});
app.get('/overwrite', (ResponseContext res) async {
app.get('/overwrite', (req, res) async {
res.statusCode = 32;
await new Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits])
.pipe(res);
@ -63,7 +65,7 @@ main() {
}
});
app.get('/error', (res) => res.addError(new StateError('wtf')));
app.get('/error', (req, res) => res.addError(new StateError('wtf')));
app.errorHandler = (e, req, res) async {
stderr..writeln(e.error)..writeln(e.stackTrace);