shelf_route 0.6.0 copy "shelf_route: ^0.6.0" to clipboard
shelf_route: ^0.6.0 copied to clipboard

outdatedDart 1 only

Routing middleware for Shelf

Router for Dart Shelf #

Build Status

Introduction #

Provides Shelf middleware for defining routes.

Shelf Route is a powerful router that makes it easy to define routes in a modular way.

Shelf Route:

  • focuses solely on routing, leaving other concerns like binding, validating, error handling etc to other middleware components
  • uses Shelf Path for storing path parameters in the Shelf Request context for interoperability with compatible middleware like Shelf Bind
  • supports defining routes heirarchically for greater modularity
  • supports custom path formats
  • supports custom handler adapters

This makes it very versatile and lets you mix and match it with your other favourite Shelf middleware components.

Using #

Basics #

You create a router using the router function

var myRouter = router();

Use the router's get method to add a route using the GET Http method

myRouter.get('/', (_) => new Response.ok("Hello World");

Use the router's handler property to obtain a Shelf Handler

var handler = myRouter.handler;

Now you can serve up your routes with Shelf IO

io.serve(handler, 'localhost', 8080);

Http Methods #

It supports all the standard http methods

myRouter..get('/', (_) => new Response.ok("Hello World"))
        ..post('/', (_) => new Response.ok("Hello World"))
        ..put('/', (_) => new Response.ok("Hello World"))
        ..delete('/', (_) => new Response.ok("Hello World"));

You can specify several methods by using add

myRouter.add('/', ['GET', 'PUT'], (_) => new Response.ok("Hello World"));

Path Parameters #

Shelf Route uses UriPattern to define the paths to match on for each route. This means you can use whatever format for the paths that you like as long as it implements this interface.

By default it uses UriTemplate which implements the powerful standard of the same name.

UriTemplate allows binding to both:

  • path segments like /greeting/fred
  • query parameters like /greeting?name=fred

It uses {parameter name} notation to denote path parameters.

myRouter.get('/{name}', (request) =>
          new Response.ok("Hello ${getPathParameter(request, 'name')}"));

Path parameters are fetched via Shelf Path's getPathParameter function.

Similarly you can also bind to query parameters

myRouter.get('/{name}{?age}', myHandler);

myHandler(request) {
  var name = getPathParameter(request, 'name');
  var age = getPathParameter(request, 'age');
  return new Response.ok("Hello $name of age $age");
}

Hierarchical Routers #

To improve modularity you can break up your routes into a series of nested routes.

For example you can add a child router for all routes starting with /banking

var rootRouter = router();

var bankingRouter = rootRouter.child('/banking');

Now you can add routes to the banking router as normal

bankingRouter
    ..get('/account/{accountNumber}', fetchAccountHandler)
    ..post('/account/{accountNumber}/deposit', makeDepositHandler);

Then serve up all the routes via the rootRouter

io.serve(rootRouter.handler, 'localhost', 8080)

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

Route Specific Middleware #

You can add additional middleware to individual routes

myRouter.get('/', (_) => new Response.ok("Hello World", middleware: logRequests());

This middelware will be applied to all requests on that route.

If you add it to a child router it will apply to all routes for that router

var bankingRouter = rootRouter.child('/banking', middleware: logRequests());

will apply to all banking routes.

Custom Path Formats #

The path arguments of all the router methods accept either:

  • a String or
  • a UriPattern

By default String value will be parsed into a UriParser which means it is expected to conform to UriTemplate.

You can also implement your own UriPattern and use that instead. For example you may prefer the : style of path variables (e.g. :name).

In addition it allows you to create uri path definitions and potentially share between client and server. e.g.

var accountPattern = new UriParser(new UriTemplate('/account/{accountNumber}'));

You can now use this when you define a route and on the client.

myRouter.get(accountPattern, (_) => new Reponse.ok("Hello World"));

Installing a Custom Path Adapter

To make it more seamless to use your own path style you can install a path adapter into the router. This will be used by all routes in this router and any child routers unless you override it somewhere.

Install the adapter by passing it to the router function.

var colonStyleAdapter = ....; // obtain the adapter from somewhere

var myRouter = router(pathAdpater: colonStyleAdapter);

Now you can use colon style path parameters

myRouter.get('/:name', (request) =>
          new Response.ok("Hello ${getPathParameter(request, 'name')}"));

Custom Handler Adapters #

You can install a custom handler adapter, which allows you to transform the handlers passed into the Router's methods. This allows for more seamless integration with other Shelf packages.

For example if you want to use ordinary Dart functions as handlers you can use a package like Shelf Bind. Shelf Bind provides such an adapter out of the box.

Install the adapter by passing it to the router function.

var myRouter = router(handlerAdapter: bind.handlerAdapter)

Now you can do

myRouter.get('/{name}', (name) => "Hello ${name}");

instead of

myRouter..get('/{name}', (request) =>
          new Response.ok("Hello ${getPathParameter(request, 'name')}"));

Note without installing the adapter you could still call Shelf Bind's bind method directly.

myRouter.get('/{name}', bind((name) => "Hello ${name}"));

Custom Route Creators #

If you have some method of creating routes then it's easy to glue in.

First implement the Routeable interface

class MyRouteCreator implements Routeable {
  void createRoutes(Router router) {
    router..get('/', (_) => new Response.ok("Hello World"))
          ..get('/greeting/{name}', (request) =>
              new Response.ok("Hello ${getPathParameter(request, 'name')}"));
  }
}

Then add it to another router

rootRouter.addRoutes(new MyRouteCreator());

Printing Routes #

It's easy to see all the routes defined for a router using the printRoutes function.

var router = r.router()
  ..get('/', (_) => new Response.ok("Hello World"))
  ..post('/', (_) => new Response.ok("Hello World"))
  ..get('/greeting/{name}{?age}', (request) {
    var name = getPathParameter(request, 'name');
    var age = getPathParameter(request, 'age');
    return new Response.ok("Hello $name of age $age");
  });
  
printRoutes(router);

prints

GET     ->      /
POST  ->      /
GET     ->      /greeting/{name}{?age}

Examples #

See more detailed examples in the example folder under the project source.

More Information #

See the wiki for more details on all the options

Contributing #

Contributions are welcome. Please:

  1. fork the repo and implement your changes with good unit test coverage of your changes
  2. create a pull request and include enough detail in the description

TODO #

See open issues.

Authors #

0
likes
0
pub points
38%
popularity

Publisher

unverified uploader

Routing middleware for Shelf

Homepage

License

unknown (LICENSE)

Dependencies

matcher, mock, path, shelf, shelf_path, uri

More

Packages that depend on shelf_route