1.0.1 • Published 8 years ago

leads v1.0.1

Weekly downloads
2
License
MIT
Repository
github
Last release
8 years ago

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.

PropertyTypeDescriptionDefault
caseSensitiveBooleanEnable case sensitivity.false, treating '/Foo' and '/foo' as the same.
mergeParamsBooleanPreserve 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
strictBooleanEnable strict routing.false, '/foo' and '/foo/' are treated the same by the router.
addHistoryBooleanapp.dispatch() optiontrue
changePathBooleanapp.dispatch() optiontrue
transitionBooleanapp.dispatch() optiontrue

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.

PropertyTypeDescriptionDefault
addHistoryBooleanIf false, the history doesn't add.true
changePathBooleanIf false, the url path doesn't change.true
datamultipleThis property is given directly to req.dataundefined
transitionbooleanIt 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

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.

PropertyTypeDescriptionDefault
baseElementElementAn element to show HTML and text, and so on.document.body
filenameStringThe default filename when downloading the file.'file'
urlBooleanTo distinguish url and string when sending file. res.download() and res.sendFile() option.true
transitionBooleanres.sendFile() option.false
cookieExpiresStringres.cookie() option.''
cookiePathStringres.cookie() and res.clearCookie() option.'/'
cookieDomainStringres.cookie() and res.clearCookie() option''
cookieSecureBooleanres.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.

The following table is about res.download() options.

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.

The following table is about res.send() options.

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.

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.

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

License

MIT