Share server-side state with the client-side of an Express app via JavaScript.
npm install express-stateExpress State
=============
[![npm Version][npm-badge]][npm]
[![Dependency Status][david-badge]][david]
[![Build Status][travis-badge]][travis]
Share configuration and state data of an [Express][] app with the client-side
via JavaScript.
[npm]: https://www.npmjs.org/package/express-state
[npm-badge]: https://img.shields.io/npm/v/express-state.svg?style=flat-square
[david]: https://david-dm.org/yahoo/express-state
[david-badge]: https://img.shields.io/david/yahoo/express-state.svg?style=flat-square
[travis]: https://travis-ci.org/yahoo/express-state
[travis-badge]: https://img.shields.io/travis/yahoo/express-state.svg?style=flat-square
[Express]: https://github.com/visionmedia/express
Overview
--------
Express State is designed to make it easy to share configuration and state data
from the server to the client. It can be used to share any data that needs to be
available to the client-side JavaScript code of the an app: e.g., the current
user, a CSRF token, model data, routes, etc.
Progressively enhanced Web apps can be built by rendering an app's initial state
on the server and using Express State as the conduit through which the server
passes data and control over to the client-side JavaScript code.
Configuration and state data are exposed to client-side JavaScript via two
methods: app.expose() and res.expose(), both of which make the data
available on a special state "locals" object for views/templates to serialize
and embed into HTML pages.
When views/templates embed this exposed data into an HTML page, it is serialized
as literal JavaScript. The JavaScript serialization format is limited to
expressions that initialize namespaces and the exposed data assigned to those
namespaces, which is a superset of JSON that includes regular expressions and
functions.
Express State was written because of the shortcomings of [express-expose][]. The
following is a list of features highlighting differences when compared withexpress-expose:
- An efficient and powerful serialization format:
Literal JavaScript is used to namespace exposed data that is a superset of
JSON and includes regular expressions and functions. This avoids the cost of
allocating and parsing large JSON strings on the client and enables things
like sharing routes defined as regular expressions with a client-side URL
router.
- Smart namespacing:
A root namespace can be set via an app's state namespace setting and it will
be prepended to namespaces passed to expose() unless they already contain it
or they start with "window.". The "global" on to which the namespaces are
created can also be controlled.
- Precise data value overrides:
Sub-values within exposed objects can be easily overridden without clobbering
the entire object. Request scoped values can even override data exposed at the
app's scope.
- Lazy serialization:
Exposed data objects are stored by reference, making them "live" and allowing
their values to be updated even after the object has been exposed. Only the
namespaces and data that are still reachable after the series of expose()
calls will be serialized. Serialization can happen at anytime, on demand, by
calling the toString() method on state "locals" objects.
When data is not going to change the {cache: true} option can be set to
eagerly serialize exposed objects, making repeated toString() calls more efficient.
- Explicit extension of each Express app: Express State's functionality has
to be explicitly added to an Express app via the exported extend() function.
This prevents problems in complex apps where multiple versions of Express
and/or multiple Express apps are used.
[app.locals]: http://expressjs.com/api.html#app.locals
[res.locals]: http://expressjs.com/api.html#res.locals
[express-expose]: https://github.com/visionmedia/express-expose
Installation
------------
Install using npm:
``shell`
$ npm install express-state
Usage
-----
To use Express State with an Express app, the app must first be extended. Use
the extend() method that Express State exports:
`javascript
var express = require('express'),
expstate = require('express-state'),
app = express();
expstate.extend(app);
`
Once extended, the app will have the app.expose() method, and response objectsres.expose()
will have the method.
Note: It's perfectly fine for the same Express app to be extended more than
once; after the first time the app is extended, the subsequent extend() calls
will be noops.
Data can be exposed at two different scopes: the app's scope, and a
request/response's scope via app.expose() and res.expose() respectively.
Express State uses Express's built-in "locals" system. When data is exposed at
the app's scope, a special app.locals.state object is created and used as theapp.expose()
backing store for all calls. Express also merges app.localsres.locals
with to create the context object in which views/templates are
rendered. This means that, by default, data exposed at the app's scope will also
be present when rendering views/templates for _all_ requests.
Express State sets up a similar relationship using prototypal inheritance where
res.locals.state inherits from app.locals.state. This means data exposed at
the request scope will also contain exposed data from the app's scope. If values
for the same namespace are exposed at both scopes, the request/response scope
takes precedence and shadows the value at the app's scope.
#### Exposing App-Scoped Data
When data that needs to be exposed to the client-side JavaScript code is _not_
request-specific and should be available to all requests, it should be exposed
at the app's scope using __app.expose()__.
The following example exposes a Flickr API key required by Flickr to identify
requests:
`javascript`
app.expose({
api_key: '02348notreal2394879137872358bla'
}, 'MY_APP.Flickr');
The client-side JavaScript code can now look up the Flickr API key at
MY_APP.Flickr.api_key when it needs to make a request to Flickr's API.
#### Exposing Request-Scoped Data
When data that needs to be exposed to the client-side JavaScript _is_
request-specific, it should be exposed at the request/response's scope using
__res.expose()__.
The following example shows how to create a middleware function to expose the
current person's Cross Site Request Forgery (CSRF) token—this is a best
practice where the CSRF is used to validate HTTP requests that mutate state:
`javascriptcookieParser()
// Add Express' packaged , session(), and csrf() middleware.
app.use(express.cookieParser());
app.use(express.session({secret: 'something secure, not this!'}));
app.use(express.csrf());
// Create a middleware function that will expose the CSRF token for the current
// request only.
app.use(function (req, res, next) {
res.expose(req.session._csrf, 'MY_APP.CSRF_TOKEN');
next();
});
`
The client-side JavaScript code can now add the X-CSRF-Token HTTP header withMY_APP.CSRF_TOKEN
the value at to all XHRs it makes to the server.
#### Increase Performance of Unchanging or Static Data
It's common to expose app-scoped data which will not change during the
lifecycle of the Express app instance. To improve per-request performance, this
unchanging/static data can be eagerly serialized and cached by setting the
__{cache: true}__ option:
`js
var CONFIG = {
hostname : 'example.com',
someOther: 'constant value'
};
app.expose(CONFIG, 'MY_APP.config', {cache: true});
`
Setting this option allows Express State to optimize the serialization process
by keeping the serialized value around and re-using it every time the
toString() method is invoked (which happens for every request.)
Note: When a large amount of data needs to be exposed to the client-side, it
is recommended to come up with a strategy where _all_ data which is common to
most/every request be exposed at the app-scope with the {cache: true} option
set.
#### Untrusted User Input
Always escape untrusted user input to protected against XSS attacks!
Express State provides a mechanism to expose configuration and state data as
first-party JavaScript, which means any untrusted user input should be properly
escaped based on the [OWASP HTML escaping recommendations][OWASP].
Express State will automatically encode any <, >, / characters within"
string values of exposed data to their Unicode counterparts during
serialization. This provides a basic level of protection against XSS attacks by
not allowing the