leads.js
leads.js is a client-side routing library that is very similar to express.js.
var app = leads();
app.get('/', function(req, res, next) {
res.send('Hello world');
});
app.dispatch('/', 'get'); // or app.get('/');
Example
Define handlers.
var app = leads();
app.all('/', indexHandler);
app.all('/user/:id', load, show);
app.all('/user/:id/profile', getProfile);
Define handlers using various path.
app.all('/foo/bar', handler);
app.all('/foo/:bar', handler);
app.all('/foo/:bar/:baz?', handler);
app.all('/ab(c)?d', handler);
app.all('/a(bc)+d', handler);
app.all('/abc/*', handler);
app.all(/\/foo\/bar/, handler);
app.all(['/abc/def', '/user/:id', /\/foo\/bar/], handler);
Define handlers using various METHOD.(See app.METHOD()).
app.all('/', handler);
app.get('/', handler);
app.post('/', handler);
app.put('/', handler);
app.delete('/', handler);
Define middleware.(See app.use())
app.use('/', middleware, errorHandler);
app.use('/admin', authenticate, router);
app.use('/blog', blogApp);
Dispatch!!
app.dispatch('/', 'all'); // or app.all('/');
app.dispatch('/user/123', 'get'); // or app.get('/user/123');
app.dispatch('/comments/post', 'post'); // or app.post('/comments/post');
Installation
$ npm install leads # for browserify
$ git clone https://github.com/webkatu/leads.js
<script src="leads.js"></script>
API
This API is referring the 4.x API of Express.
leads()
This is a main function that creates an application.
var app = leads();
leads([options])
It creates an instance of Application.
var app = leads({
caseSensitive: false,
mergeParams: false,
strict: false,
});
The optional options parameter specifies the behavior of the router in app.
| Property | Type | Description | Default |
|---|---|---|---|
| caseSensitive | Boolean | Enable case sensitivity. | false, treating '/Foo' and '/foo' as the same. |
| mergeParams | Boolean | Preserve the req.params values from the parent router. If the parent and the child have conflicting param names, the child’s value take precedence. | false |
| strict | Boolean | Enable strict routing. | false, '/foo' and '/foo/' are treated the same by the router. |
| addHistory | Boolean | app.dispatch() option | true |
| changePath | Boolean | app.dispatch() option | true |
| transition | Boolean | app.dispatch() option | true |
leads.Router([options])
It creates an instance of Router.
The options is the same as options of leads([options]).
Application
This object is subclass of Router.
app.defaults
This property is an object that has properties, caseSensitive, mergeParams, strict, addHistory, changePath, transition.
var app = leads({caseSensitive: true});
console.log(app.defaults.caseSensitive); // true
app.defaults.caseSensitive = false;
console.log(app.defaults.caseSensitive); // false
app.all(path, callback[, callback ...])
It registers route handler(s).
It defines a route mapping path to the given callback(s). Each callback is given three arguments, request, response, next.
This method is one of the app.METHOD() methods.
app.all('/', index);
app.all('*', all);
app.all('/user/:id', authenticate, show);
The leads.js is using internally path-to-regexp to match the path.
app.all(path[, options])
app.all(path, options) is same as app.dispatch(path, 'all', options).
app.dispatch(path[, method][, options])
app.dispatch() invokes middleware and matching route handlers(callbacks).
And, it changes the url path by History API.
app.dispatch(path) is same as app.dispatch(path, 'all') and app.all(path).
The second param is specified HTTP method. However, leads.js doesn't do actually HTTP request beacuse leads.js is client-side router. This is one of the mere conditions when matching routes.
app.post('/greet', function(req, res, next) {
console.log('Hello');
next();
});
app.get('/greet', function(req, res, next) {
console.log('Hi');
});
app.dispatch('/greet'); // same as app.all('/greet')
/* console
Hello
Hi
*/
app.dispatch('/greet', 'get'); // same as app.get('/greet')
/* console
Hi
*/
The third param is dispatch options.
| Property | Type | Description | Default |
|---|---|---|---|
| addHistory | Boolean | If false, the history doesn't add. | true |
| changePath | Boolean | If false, the url path doesn't change. | true |
| data | multiple | This property is given directly to req.data | undefined |
| transition | boolean | It transition page if you specify other origin url to path. If false, it doesn't transition. | true |
About addHistory and changePath.
app.get('/greet', function(req, res, next) {
console.log('Hi');
});
app.dispatch('/greet', 'get', {
addHistory: false,
changePath: false,
}); // URL and History don't change
About data.
app.post('/signup', function(req, res, next) {
console.log(req.data);
});
app.dispatch('/signup', 'post', {
data: new FormData(),
});
/* console
FormData {}
*/
About transition.
app.dispatch('http://www.google.com', null, {
transition: false
}); // not occur anything.
app.dispatch('http://www.google.com'); // transition to the google.
app.METHOD(path, callback[, callback ...])
This register route handler(s).
As with app.all(), it defines a route mapping path to the given callback(s).
Specify HTTP method name in the METHOD.
app.get('/image', load, show);
app.post('/user/:id', authenticate);
app.put('/edit', send, show);
The HTTP method name is given to req.method.
Supported methods
- get
- post
- head
- put
- delete
- options
app.METHOD(path[, options])
This is same as app.dispatch(path, METHOD, options).
app.param(name, callback)
This registers a route parameter handler.
When it matches the route of path that contains the parameters, callback defined by app.param() is called first.
The callback is given four arguments, request, response, next and paramValue.
app.get('/user/:id', function(req, res, next) {
console.log('Hi user');
});
app.param('id', function(req, res, next, value) {
console.log('ID is ' + value);
next();
});
app.dispatch('/user/123');
/* console
ID is 123
Hi user
*/
Same param callback is not called in succession.
app.param('id', function(req, res, next, value) {
console.log('ID is ' + value);
next();
});
app.get('/user/:id', function(req, res, next) {
console.log('This matches');
next();
});
app.get('/user/:id', function(req, res, next) {
console.log('This matches too');
});
app.dispatch('/user/456');
/* console
ID is 456
This matches
This matches too
*/
It is also possible to give an array to name such as app.param(['class', 'id'], callback)
Please refer to path-to-regexp about path that contains the parameters.
app.route(path)
app.route() returns a route object mapping the path.
The route object has method of app.METHOD(), and it defines callback by method chain.
Use app.route() to avoid duplicate route names.
app.route('/blog/article')
.all(function(req, res, next) {
console.log('Hi');
next();
})
.get(function(req, res) {
console.log('Get article');
})
.post(function(req, res) {
console.log('Post article');
})
.delete(function(req, res) {
console.log('Delete article');
});
app.use([path, ]function[, function ...])
It mounts the middleware function(s).
Each middleware function is given three arguments, request, response, next.
If the first param is path, middleware is called when it matches path prefix.
For example, app.use('/blog',middleware) will match /blog, /blog/articles, /apple/articles/123, and so on.
If path is not specified, it defaults to '/'.
app.use(function(req, res, next) { // same as app.use('/', ...)
console.log('This is called every time');
});
app.use() is also possible to mount router and sub-app as well as function.
var router = leads.Router();
router.get('/', function(req, res, next) {
console.log('Hi');
});
router.get('/Hello', function(req, res, next) {
console.log('Hello');
});
app.use('/greet', router);
var subApp = leads();
app.use('/blog', subApp);
In addition, app.use() can mount error handler. The error handler function is given four arguments, error, request, response, next.
The error handler will be called when given a value other than undefined to next().
app.use(function(err, req, res, next) {
console.log(err);
});
app.get('/', function(req, res, next) {
next('Error Occurred');
});
app.get('/', function(req, res, next) {
console.log("I won't be called.");
});
app.dispatch('/');
/* console
Error Occurred
*/
You can specify various types of path, a path string, a path pattern, a named parameter, a regular expression, an array of combinations thereof.
From Express4.x table
| Type | Example |
|---|---|
| Path |
This will match paths starting with /abcd.
app.use('/abcd', function (req, res, next) {
next();
});
|
| Path Pattern |
This will match paths starting with /abcd and /abd.
app.use('/ab(c)?d', function (req, res, next) {
next();
});
This will match paths starting with /abcd, /abbcd, /abbbbbcd, and so on.
app.use('/a(b)+cd', function (req, res, next) {
next();
});
This will match paths starting with /abcd, /abxcd, /abFOOcd, /abbArcd, and so on.
app.use('/ab(.*)cd', function (req, res, next) {
next();
});
This will match paths starting with /ad and /abcd.
app.use('/a(bc)?d', function (req, res, next) {
next();
});
|
| Named Parameter |
This will match paths starting with /abc/xyz, /1234/5678, everything/everything.
app.use('/:foo/:bar', function(req, res, next) {
next();
});
|
| Regular Expression |
This will match paths starting with /abc and /xyz.
app.use(/\/abc|\/xyz/, function (req, res, next) {
next();
});
|
| Array |
This will match paths starting with /abcd, /xyza, /lmn, and /pqr.
app.use(['/abcd', '/xyza', /\/lmn|\/pqr/], function (req, res, next) {
next();
});
|
app.use() can mount plural middleware. However, it does not support to give array parameter like express app.use().
var subApp = leads();
var r1 = leads.Router();
var r2 = leads.Router();
var f = function(req, res, next) { next(); }
app.use(subApp, r1, r2, f); // possible;
app.use(subApp, [r1, r2], f) // impossible;
next()
This is a function given to a route handler and a middleware function for calling the next route handler.
The error handler will be called if you give a value other than undefined to next().
However, if specifying next('route'), it will skip to next route.
app.get('/', function(req, res, next) {
next('route');
}, function(req, res, next) {
console.log(1);
next();
}, function(req, res, next) {
console.log(2);
next();
});
app.get('/', function(req, res, next) {
console.log(3);
});
app.dispatch('/');
/* console
3
*/
When calling the next('route') in parameter handler, it will skip only subsequent parameter handlers.
app.param('id', function(req, res, next, value) {
next('route');
});
app.param('id', function(req, res, next, value) {
console.log(1);
next();
});
app.param('id', function(req, res, next, value) {
console.log(2);
next();
});
app.get('/:id', function(req, res, next) {
console.log(3);
});
app.dispatch('/123');
/* console
3
*/
Request
This instance is given to a route handler and a middleware function.
When dispatching, it is created and contain context.
req.app
req.app can access an app object or a router object from the inside of middleware that has been mounted by them.
var subApp = leads();
subApp.get('/', function(req, res, next) {
console.log(req.app === subApp); // true
next();
});
var r = leads.Router();
r.get('/', function(req, res, next) {
console.log(req.app === r); // true
});
app.use(subApp, r);
req.baseUrl
req.baseUrl is path of middleware that mounted by app.use().
var r = leads.Router();
r.use('/123', function(req, res, next) {
console.log(req.baseUrl); // /user/123
next();
});
r.get('/123', function(req, res, next) {
console.log(req.baseUrl); // /user
});
app.use('/user', r);
app.dispatch('/user/123');
/* console
/user/123
/user
*/
In other words, the req.baseUrl returns matched string.
app.use([/\/\d+/, '/a(bc)+d'], function(req, res, next) {
console.log(req.baseUrl);
});
app.dispatch('/1111/2222'); // 1111;
app.dispatch('/1234/5678/9'); // 1234;
app.dispatch('/abcbcd/ef'); // abcdcd;
req.cookies
It returns cookie object.
// cookie => name=Bob
req.cookies.name // => Bob;
It is dynamic and read-only.
res.cookie('name', 'Bob');
req.cookies.name; => Bob
res.cookie('name', 'John');
req.cookies.name; => John
req.data
When dispatched, req.data is given data by the dispatch options.
app.all('/', function(req, res, next) {
console.log(req.data);
});
app.dispatch('/', null, { data: 'foo' });
/* console
foo
*/
req.dispatcher
req.dispatcher is app object or router object that executed the dispatch method.
var r = leads.Router();
r.all('/', function(req, res, next) {
console.log(req.dispatcher === app); // true;
});
app.use(r);
app.dispatch('/');
req.hash
// app.dispatch('http://example.com/foo?page=12#bar');
req.hash // => #bar
req.host
// app.dispatch('http://example.com/foo?page=12#bar');
req.host // => example.com
req.hostname
// app.dispatch('http://example.com/foo?page=12#bar');
req.hostname // => example.com
req.href
// When origin is 'http://example.com'
// app.dispatch('/foo?page=12#bar');
req.href // => http://example.com/foo?page=12#bar
req.method
req.method is http method name specified in app.dispatch();
// app.dispatch('/');
req.method // => all
// app.dispatch('/', 'get');
req.method // => get
// app.post('/');
req.method // => post
req.origin
// app.dispatch('http://example.com/foo?page=12#bar');
req.origin // => http://example.com
req.originalUrl
req.originalUrl is path specified in app.dispatch();
// app.dispatch('/foo/bar');
req.originalUrl // => /foo/bar
//app.dispatch('http://example.com/foo?page=12#bar');
req.originalUrl // => http://example.com/foo?page=12#bar
req.params
This property is an object containing properties mapped to the named route parameters.
app.use('/:foo/:bar', function(req, res, next) {
console.log(req.params);
});
app.dispatch('/blog/articles');
/* console
{ foo: 'blog', bar: 'articles' }
*/
When you use an unnamed parameters such as a path pattern or a regular expression using brackets, it will be numerically indexed.
app.use('/fo(o)+/b(ar)?/(.*)', function(req, res, next) {
console.log(req.params);
next();
});
app.use(/\/(foo)\/(bar)/, function(req, res, next) {
console.log(req.params);
});
app.dispatch('/foo/bar/baz/123');
/* console
{ 0: "o", 1: "ar", 2: "baz/123" }
{ 0: "foo", 1: "bar" }
*/
Refer to path-to-regexp.
req.path
// app.dispatch('http://example.com/foo?page=12#bar');
req.path // => /foo?page=12
req.pathname
// app.dispatch('http://example.com/foo?page=12#bar');
req.pathname // => /foo
req.port
It returns '' if port is number 80.
req.protocol
// app.dispatch('http://example.com/foo?page=12#bar');
req.protocol // => http:
req.query
This property is query object of querystring.parse();
// app.dispatch('http://example.com/foo?page=12#bar');
req.query.page // 12
req.search
// app.dispatch('http://example.com/foo?page=12#bar');
req.search // => ?page=12:
req.secure
If protocol is https:, req.secure returns true.
Response
This instance is given to a route handler and a middleware function.
This object has various and useful methods. However, they might be not necessarily required. If you want using minimum function, use leads-router.
res.defaults
This property is an object to set the default options.
| Property | Type | Description | Default |
|---|---|---|---|
| baseElement | Element | An element to show HTML and text, and so on. | document.body |
| filename | String | The default filename when downloading the file. | 'file' |
| url | Boolean | To distinguish url and string when sending file. res.download() and res.sendFile() option. | true |
| transition | Boolean | res.sendFile() option. | false |
| cookieExpires | String | res.cookie() option. | '' |
| cookiePath | String | res.cookie() and res.clearCookie() option. | '/' |
| cookieDomain | String | res.cookie() and res.clearCookie() option | '' |
| cookieSecure | Boolean | res.cookie() and res.clearCookie() option. | false |
Example of setting way.
app.use(function(req, res, next) {
res.defaults = {
filename: 'filename.txt',
transition: true,
cookieExpires: 7,
cookiePath: ''
};
});
res.cookie(name, value[, options])
res.cookie() create a cookie.
res.cookie('name', 'value', { expires: 7, path: '' });
This method is internally using js-cookie. res.cookie(name, value, options) is the same as Cookies.set(name, value, options) of js-cookie. Please refer to it.
The following are properties of options.
- expires
- path
- domain
- secure
res.clearCookie(name[, options])
res.clearCookie() delete a cookie.
This method is the same as Cookies.remove(name, options) of js-cookie.
The following are properties of options.
- path
- domain
- secure
"IMPORTANT! when deleting a cookie, you must pass the exact same path, domain and secure attributes that were used to set the cookie, unless you're relying on the default attributes."
res.download(file[, options])
This method downloads a file.
res.download('/img/cat.png')
In addition to the path, it can specify various types to the file. See the following table.
| Type | Description | Example |
|---|---|---|
| ArrayBuffer | It downloads the binary file. Default mimetype is 'application/octet-stream'. |
res.download(new ArrayBuffer()) |
| Blob | It downloads the blob. |
res.download(new Blob(['foo'], { type: 'text/plain'}))
|
| Object | It downloads as the JSON. Default mimetype is 'application/json'. |
res.download({ foo: 'bar' })
|
| URL | It downloads the file of url. It should be the same origin. If you want to specify cross origin, the server-side must enable CORS. |
res.download('/img/cat.png')
|
| String | It downloads the text. Default mimetype is 'text/plain'. You should set to options.url = false to distinguish between the URL and text. |
res.download('foobar', { url: false })
|
The following table is about res.download() options.
| Property | Type | Description | Default | Example |
|---|---|---|---|---|
| error | Function | When it failed downloading, this function is called with argments that is error object. |
res.dowload('http://example.com', {
error: function(e) {
console.log(e);
}
})
|
|
| filename | String | File name. | 'file' |
res.download({ foo: 'bar' }, {
filename: 'foobar.json'
})
|
| type | String | File mimetype. |
res.download(new ArrayBuffer(), {
filename: 'img.png',
type: 'image/png'
})
|
|
| url | Boolean | Distinguish between the URL and text. | true |
res.download('/image/cat.png', { url: true })
res.download('foobar', { url: false })
|
res.send(data[, options])
It shows the data on document.
res.send('send text');
res.send('<p>send HTML</p>');
res.send(Element);
res.send(document);
res.send({ foo: 'bar' });
res.send(new ArrayBuffer());
res.send(blob);
The following table is about the data.
| Type | Description | Example |
|---|---|---|
| Document | document childnodes are replaced to the new document childnodes. |
var xhr = new XMLHttpRequest();
xhr.open('GET', '/');
xhr.responseType = 'document';
xhr.onload = function() {
res.send(xhr.response);
};
xhr.send();
|
| Element | Base element appends the element. |
var p = document.createElement('p');
p.innerHTML = 'foo<span>bar</span>';
res.send(p);
/*
<body>
<p>foo<span>bar</span></p>
</body>
*/
|
| String | It gives to base element innerHTML. |
res.send('foobar');
// <body>foobar</body>
res.send('<p>foobar</p>');
// <body><p>foobar</p>
|
| ArrayBuffer | Refer to res.sendFile() |
res.send(new ArrayBuffer()); |
| Blob | Refer to res.sendFile() |
res.send(new Blob(['foobar'], { type: 'text/plain' }));
|
| Object | Refer to res.sendFile() |
res.send({ foo: 'bar' });
|
The following table is about res.send() options.
| Property | Type | Description | Default | Example |
|---|---|---|---|---|
| baseElement | Element | An element to show data of HTML and text and so on. | document.body |
<body> <div id="main"></div> </body>
var main = document.getElementById('main');
res.send('Hello', { baseElement: main });
/*
<body>
<div id="main">Hello</div>
</body>
*/
|
| filename | String | For IE. Refer to res.sendFile(). | 'file' | |
| title | String | Document title. If not specify, not change title. |
res.send('Hello', { title: 'Hello' });
|
|
| transition. | Boolean | Page transition. Refer to res.sendFile(). | false | |
| type | String | mimetype. Refer to res.sendFile(). |
res.sendFile(file[, options])
(Experimental method)
It shows the file using <object></object>.
res.sendFile('/image/cat.png');
/*
<body>
<object data="/image/cat.png"></object>
</body>
*/
It can specify the following types to the file like res.download().
- ArrayBuffer
- Blob
- Object
- URL
- String
If the file isn't URL, res.sendFile() creates blob URL from the file. However IE doesn't create blob URL. Therefore IE directly downloads blob.
The following table is about res.sendFile() options.
| Property | Type | Description | Default |
|---|---|---|---|
| baseElement | Element | An element to append<object></object>. |
document.body |
| filename | String | Filename for IE when downloading blob.. | 'file' |
| title | String | Document title. If not specify, not change title. | |
| transition. | Boolean | If true, page transitions to directly show the file. | false |
| type | String | Mimetype. It is given to <object type="">. |
|
| url | Boolean | Distinguish between the URL and text. | true |
res.sendStatus(status[, options])
It sends HTTP status and the status message.
res.sendStatus(403) // <body>403 Forbidden</body>
res.sendStatus(404) // <body>404 Not Found</body>
res.sendStatus(500) // <body>500 Internal Server Error</body>
Please refer to httpStatusTable about status message.
If you specify non-existent status, it returns the status number.
res.sendStatus(1234) // <body>1234</body>
You can specify any message.
res.sendStatus(404, { message: 'ERROR 404' }) // <body>ERROR 404</body>
The following table is about res.sendStatus() options.
| Property | Type | Description | Default |
|---|---|---|---|
| baseElement | Element | An element to show status message. | document.body |
| title | String | Document title. If not specify, it change to status message. If you specify options.message, the title will be the its message. |
The same as the status message. |
| message | String | You can specify any message to show. |
res.redirect(path)
It redirects to path.
res.redirect('./');
res.redirect('../');
res.redirect('http://www.google.com');
If you specify res.redirect('back'), history back.
Router
Router is a core object of leads.js.
var router = leads.Router();
router.get('/', function(req, res, next) {
/* code */
});
app.use('/user', router);
It is inherited to Application.
router.defaults
See app.defaults.
router.all(path, callback[, callback ...])
See app.all().
router.all(path[, options])
See app.all().
router.dispatch(path[, method][, options])
See app.dispatch().
router.METHOD(path, callback[, callback ...])
See app.METHOD().
router.METHOD(path[, options])
See app.METHOD().
router.param(name, callback)
See app.param().
router.route(path)
See app.route().
router.use([path, ]function[, function ...])
See app.use().
Support
Tested on IE11, Chrome, Firefox.
If you want to support IE10+, use leads-router.
Author
- Twitter @vinyufi
- Blog webkatu.com