route-mappings v0.7.4
RouteMappings
Function factory to create nested definitions of routes, with namespaces and resources support.
var RouteMappings = require('route-mappings');
// create a new RouteMappings instance
var routeMappings = RouteMappings()
.get('/', { to: 'home_handler' })
.get('/login', { to: 'login_handler' })
.delete('/logout', { to: 'logout_handler' })
.resources('/articles')
.namespace('/account', function() {
return RouteMappings()
.get('/', { to: 'show_account_handler' })
.put('/', { to: 'update_account_handler' })
.get('/edit', { to: 'edit_account_handler' });
});
// print all registered routes
routeMappings.routes.forEach(function(route) {
// 1) the "to" option is not used internally, but this demonstrate you can pass whatever you want
// 2) all routes have a "handler" property which holds its namespace,
// which is useful on resource definitions since they can't be named directly
console.log(route.verb.toUpperCase(), route.path, route.to || route.handler.join('_'));
});
// access url() helper for building routes
console.log(routeMappings.mappings.root.url());
console.log(routeMappings.mappings.login.url());
console.log(routeMappings.mappings.logout.url());
console.log(routeMappings.mappings.account.url());
console.log(routeMappings.mappings.account.edit.url());
console.log(routeMappings.mappings.articles.edit.url(42));Instance settings
RouteMappings(options: Object) — Create a new function factory from given options:
RESOURCE_KEY: String— Used on resources to name the/<id>segment (default is:id)On nested resources it becomes from
:idto:resource_idautomatically, so you'll end up with something like this/posts/:post_id/comments/:idPARAMS_PATTERN: RegExp— Used for match-and-replace params from given routes (default is/[:*](\w+)/g)Note the global
gflag and the first capture(\w+)on the regular expression, don't forget it, otherwise all stuff related with urls won't work as expected.SUPPORTED_ACTIONS: Object— Settings for translating resource actions to routes (defaults are in ./lib/index.js#L8-L16)If you provide your own options don't forget to use
:idas theRESOURCE_KEYis defined, otherwise replacements won't occur.
More options?
Any additional option found will be copied and stored within the RouteMappings instance, then all options will be merged through any defined route on compilation time.
To create another RouteMappings instance with all its parent's options you can use the following:
var $ = RouteMappings({ use: ['root'] })
.get('/', { as: 'home' })
// all factories will receive the same instance
.namespace('/admin', function(RouteMappings) {
return RouteMappings({ use: ['auth'] })
.resources('/posts');
})
// using the original factory will not inherit anything
.namespace('/articles', function() {
return RouteMappings()
// resources shall be RouteMappings instances too!
.resources('/comments', { use: ['other'] });
}).mappings;
$.home.use; // ['root']
$.admin.posts.use; // ['root', 'auth']
$.articles.comments.use; // ['other']Methods
<http-verb>(path: String, params: Object)— Basic method for call any HTTP method, e.g.get('/', { as: 'root' })The
asoption is used for named routes, if missing it will be constructed from the route name and handler.Internally it will add a
handleroption containing all parent handlers (if present) from a single route, all other values will be passed as is.namespace(path: String, factory: <Function|Object>)— This method allows to mount other route mappings (instances) into the current instance.The
factorycan be also a function which returns a new RouteMappings instance when called.resources(...path: <String|Array>, params: Object, factory: <Function|Object>)— Shortcut for creating route mappings from resourcesIn fact, a resource is a new RouteMappings instance mounted within the given namespace.
Nesting support
Consider the following example:
var $ = RouteMappings()
.resources('/Parent', function () {
return RouteMappings()
.get('/Section')
.resources('/Children');
})
.namespace('/Section', function () {
return RouteMappings()
.resources('/Parent', function () {
return RouteMappings()
.resources('/Children');
});
}).mappings;Where:
$.Parent.Children.pathwill be/parent/:parent_id/children$.Parent.Children.handlerwill be['Children']$.Parent.Section.pathwill be/parent/section$.Section.Parent.Children.pathwill be/section/parent/:parent_id/children$.Section.Parent.Children.handlerwill be['Section', 'Children']
As you can see, nested resources will not carry their parent details when building handlers, only namespaces are taken into account for that.
Paths are normalized to be human friendly, all
PascalCasesegments will be mapped aspascal-case.
URL mappings support
All http-verbs can define its own alias name with as, e.g:
var $ = RouteMappings()
.get('/', { as: 'myUrl' })
.namespace('/Section', function() {
return RouteMappings()
.get('/:slug')
.resources('/Top');
}).mappings;
[$.myUrl.verb, $.myUrl.path];
// ['get', '/']
[$.Section.verb, $.myUrl.path];
// ['get', '/section/:slug']
[$.Section.Top.verb, $.Section.Top.path];
// ['get', '/section/top']
[$.Section.Top.update.verb, $.Section.Top.update.path];
// ['put', '/section/top/:id']You can access to any defined route through routeMappings.mappings property.
When a route has no alias defined, or, when the route is created automatically (e.g. resources) the alias name will be generated from the its path.
Casing is preserved from this conversion, e.g.
/SubSection/Pagewould map to/sub-section/pageand$.SubSection.Pagerespectively.
Properties
tree: Array— Read-only property containing all the route definitionsroutes: Array— Read-only property containing all the route definitions as a flattened listEach route will have, at least:
as— The computed name for accesing this route throughmappings, if missing it will be computed from the route detailsverb— The specified HTTP verb uses from<http-verb>()calls, if missing you can assume the route isGETpath— The provided path from any call, as is, without modificationshandler— The computed handler for each single route as array
mappings: Object— Read-only property containing a tree of all named routes namespacedEach route hold the same data as accesing
routesbut with an extraurl()function, useful for generating routes from given paths.Given
/foo/:baryou can useurl(123)to produce/foo/123, if you pass an object it should be called asurl({ bar: 123 })to produce the same url.
Integration example
// example modules
var path = require('path'),
express = require('express');
var expressRouter = express.Router();
// iterate all compiled routes
routeMappings.routes.forEach(function(route) {
// append custom "to" handler
if (route.to) {
route.handler.push(route.to);
}
// hipotetical modules as controllers
var controller = path.join(__dirname, 'controllers', route.handler.join('/') + '.js');
// load the resolved module
var handler = require(controller);
// specific action/function from module?
if (route.action) {
handler = handler[route.action];
}
// finally, we can register the route and handler
expressRouter.route(route.path)[route.verb](handler);
});Made with ♥
3 years ago
3 years ago
3 years ago
6 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
