shelf_route 0.1.1+1 copy "shelf_route: ^0.1.1+1" to clipboard
shelf_route: ^0.1.1+1 copied to clipboard

outdatedDart 1 only

Routing middleware for Shelf

Router for Dart Shelf #

Introduction #

Provides Shelf middleware for defining routes.

Shelf Route makes it easy to define routes in a modular way. How?

  • A Router is simply a Shelf Middleware component.
  • You can define a single Router for your whole application or as many as you like in a heirarchical structure.
  • When a Router passes a request to a child route it first modifies the request as follows:
    • The route's path is removed from the start of pathInfo. e.g. /banking/accounts -> /accounts
    • The route's path is appended to the scriptName. e.g. / -> /banking
    • That supports modularity in the child routes as the pathInfo only contains the path relative to that component.

Using #

Basics #

First set up a little test handler that just echos the request

shelf.Response _echoRequest(shelf.Request request) {
  return new shelf.Response.ok('Request for "${request.pathInfo}"');
}

To route all requests that start with /public to this handler

var router = (route.router()
    ..addRoute(_echoRequest, path: '/public'))
    .handler;

Then you can create a simple server passing in the router you just created

io.serve(router, 'localhost', 8080).then((server) {
    print('Serving at http://${server.address.host}:${server.port}');
});

To route only 'GET' requests

var router = (route.router()
    ..addRoute(_echoRequest, path: '/public', method: 'GET'))
    .handler;

or better still the simpler form

var router = (route.router()
    ..get('/public', _echoRequest))
    .handler;

Path Variables #

You can include variables in the paths that are passed to the router. Path variables start with a :. For example :name is a path variable called name.

To route a 'GET' with a variable for the users name

var router = (route.router()
    ..get('/user/:name', _echoRequest))
    .handler;

To POST a new deposit into an account resource

var router = (route.router()
    ..post('/account/:accountNumber/deposit', _echoRequest))
    .handler;

In a future release you will be able to specify constraints like type and regex on path variables. Currently only strings are supported.

You can then access these variables from inside the handler. Currently they are added to the request headers with a prefix of shelf.route.. So in the account example

request.headers['shelf.route.accountNumber']

will return the value POSTed.

Note that once shelf supports extra parameters on messages Shelf Route will switch over to using them and deprecate the use of headers.

Heirarchical Routers #

To improve modularity you can break up your routes into a series of nested routes. For example you can set up a top level /banking route

var router = route.router();
var bankingRouter = router.addChildRouter('/banking');
var handler = router.handler;

and then set up the bankingRouter

bankingRouter
    ..post('/account/:accountNumber/deposit', _echoRequest)
    .handler;

Note in this case the full path of the deposit resource is actually /banking/account/:accountNumber/deposit.

To try this out, fire up the server and do

curl -d 'lots of money' http://localhost:8080/banking/account/1235/deposit

More Complex Example #

The following example shows several of these features together.

Full source at example/routing_example.dart

import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_route/shelf_route.dart' as route;

void main() {
  var publicRoute = const shelf.Stack()
      .addHandler(_echoRequest);

  var router = (route.router()
      ..addRoute(publicRoute, path: '/public')
      ..addRoute(_bankingRoutes(), path: '/banking'))
      .handler;

  var handler = const shelf.Stack()
      .addMiddleware(shelf.logRequests())
      .addHandler(router);

  io.serve(handler, 'localhost', 8080).then((server) {
    print('Serving at http://${server.address.host}:${server.port}');
  });
}

shelf.Response _echoRequest(shelf.Request request) {
  return new shelf.Response.ok('Request for "${request.pathInfo}"');
}

// supports modularity with routes. i.e. here the banking section has it's own routes
// these are relative to where the main router places them
shelf.Handler _bankingRoutes() {
  var transfersRoute = const shelf.Stack()
      .addHandler(_echoRequest);

  var bankingRouter = (route.router()
      ..addRoute(_accountsRoute(), path: '/account')
      ..addRoute(transfersRoute, path: '/transfer'))
      .handler;

  var bankingRoute = const shelf.Stack()
//      .addMiddleware(authenticator); // obviously they would be authenticated
      .addHandler(bankingRouter);

  return bankingRoute;
}

// all accounts
shelf.Handler _accountsRoute() {
  return (route.router()
      ..addRoute(_individualAccountRoute(), path: '/:accountNumber')
      ..get('/', _searchAccounts))
      .handler;
}

// a single account with an account number. Note accountNumber is now
// in request.extraParams
shelf.Handler _individualAccountRoute() {
  return (route.router()
      ..get('/', _fetchAccount)
      ..post('/deposit', _deposit))
      .handler;
}

shelf.Response _fetchAccount(shelf.Request request) {
  return new shelf.Response.ok(
      "Fetch account for acct num ${request.headers['shelf.route.accountNumber']}");
}

shelf.Response _deposit(shelf.Request request) {
  return new shelf.Response.ok(
      "Deposit into account for acct num ${request.headers['shelf.route.accountNumber']}");
}

shelf.Response _searchAccounts(shelf.Request request) {
  return new shelf.Response.ok("Search accounts");
}

TODO #

Authors #

0
likes
0
pub points
38%
popularity

Publisher

unverified uploader

Routing middleware for Shelf

Homepage

License

unknown (LICENSE)

Dependencies

matcher, path, shelf

More

Packages that depend on shelf_route