justinfagnani / route

A client + server routing library for Dart
BSD 3-Clause "New" or "Revised" License
114 stars 40 forks source link

Allow request-specific context data to be passed to handlers (Server) #18

Open justinfagnani opened 11 years ago

justinfagnani commented 11 years ago

Request handlers can only take a HttpRequest as its single parameter. Many applications will need to add state to the request as it is processed by filters for use in handlers.

One option is to inject objects into a function that accepts more than a HttpRequest, and transform the function into a request handler. Dependency Injection could be used to pass along the needed objects.

RequestHandler inject(Function f);

HttpServer.bind().then((server) {
  var router = new Router(server)
    ..filter(matchesAny(allUrls), authFilter)
    ..serve(homeUrl).listen(inject(serveHome));
}

void serveHome(HttpRequest request, User user) {
  // ...
}
justinfagnani commented 11 years ago

inject() isn't really sufficient as it needs some collaboration with the Router so the router can pass the request-specific data. If inject() also took a reference to the router it could request injection from the router based on the HttpRequest it received, but that makes the API have even more boilerplate-y.

Another approach is to return a special Stream from serve() that has an additional method that works like listen() but takes any function. This opens up some interesting possibilities for writing very simple handlers that don't have to be aware of HttpRequest or HttpResponse because we can inject other proxies for the request and response streams, or even use the return value.

Example:

HttpServer.bind().then(server) {
  var router = new Router(server);
  router.serve(resourceUrl).handle((String resourceID) => 
      database.get(resourceID).then(json.stringify));
});

Here we parse resourceID from the request path automatically (requires named URL parameters, not just positional like we have now) and add it to the injector for this request. The handler is invoked with resourceID, and it returns a Future. The router takes the string and writes it to the HttpResponse. If the author wants to set the mime-type or status code they can either inject the HttpResponse, or we could add a light-weight Response object that holds the response body as a string and a few of the common headers.

We could inject the following to handler functions: