# express-state **Repository Path**: mirrors_yahoo/express-state ## Basic Information - **Project Name**: express-state - **Description**: Share configuration and state data of an Express app with the client-side via JavaScript. - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-11-30 - **Last Updated**: 2026-10-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README Express 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 -------- ### Goals 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. ### How It Works 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. ### Features Express State was written because of the shortcomings of [express-expose][]. The following is a list of features highlighting differences when compared with `express-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 ----- ### Extending an Express App 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 objects will have the `res.expose()` 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. ### Exposing Data 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 the backing store for all `app.expose()` calls. Express also merges `app.locals` with `res.locals` 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: ```javascript // Add Express' packaged `cookieParser()`, `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 with the value at `MY_APP.CSRF_TOKEN` 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 `" ``` **Note:** In this example triple-mustaches (`{{{ }}}`) are used so that Handlebars does _not_ HTML-escape the value. Handlebars will automatically call the `toString()` method on the special `state` object, which renders the JavaScript. See the [Untrusted User Input][] section above. [Handlebars]: http://handlebarsjs.com/ [OWASP]: http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet [Untrusted User Input]: #untrusted-user-input [Exposing Functions]: #exposing-functions Examples -------- ### [Basic Usage][] A runnable example of the most basic Express app that uses Express State. [Basic Usage]: https://github.com/yahoo/express-state/tree/master/examples/basic API --- ### Configuration and Defaults The following properties are exported from the Express State module. Assigning values to these properties affects all Express apps extended with this Express State module instance. To set these values for a specific app, use [App Settings][]. #### `local = "state"` A string property name on `app.locals` and `res.locals` where Express State creates its special objects used to store and serialize exposed data. By default, Express State will create these objects: * `app.locals.state` * `res.locals.state` #### `namespace = null` The root namespace is a string that should be prepended on the namespaces provided to `app.expose()` and `res.expose()` method calls. By default, no root namespace is used, and namespaces are created directly on the global (`window`) object in the browser. See [Setting a Root Namespace][] for more details. ### App Settings The following settings use the [Express Settings][] feature and only apply to the app which they are `set()`. These app settings take precedence over the Express State's global configuration settings above. #### `state local` Use `state local` to create a property on `app.locals` and `res.locals` where Express State creates its special objects used to store and serialize exposed data. By default, no value is set, so Express State's exported `local` configuration value is used. The following example sets the locals properties to `app.locals.exposed` and `res.locals.exposed`: ```javascript app.set('state local', 'exposed'); ``` #### `state namespace` Use `state namespace` to create a root namespace that should be prepended on the namespaces provided to `app.expose()` and `res.expose()` method calls. By default, no root namespace is used, and namespaces are created directly on the global (`window`) object in the browser. The following example sets the root namespace to `"MY_APP"`: ```javascript app.set('state namespace', 'MY_APP'); ``` See [Setting a Root Namespace][] for more details. ### Static Methods #### `extend (app)` This function is exported from the Express State module that extends the functionality of the specified Express `app` by adding the two `expose()` methods: `app.expose()` and `res.expose()`. 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. **Parameters:** * `app`: Express app instance to extend with Express State's functionality. See [Extending an Express App][] for more details. ### Methods #### `app.expose (obj, [namespace], [options])` #### `res.expose (obj, [namespace], [options])` The two `expose()` methods behave the same, the only difference being what scope the data is exposed, either the app's or at the request's scope. These two methods are used to expose configuration and state to client-side JavaScript by making the data available on a special `state` "locals" object for views/templates to serialize and embed into HTML pages. See the [Untrusted User Input][] section above, and make sure untrusted user input is _always_ escaped before it passed to this method. **Parameters:** * `obj`: Any serializable JavaScript object to be exposed to the client-side. * `[namespace]`: Optional string namespace where the `obj` should be exposed. This namespace will be prefixed with any configured root namespace unless it already contains the root namespace or starts with `"window."`. * `[options]`: Options which can be specified as either the second or third argument to this method, and may contain the following: * `[cache]`: Optional boolean to signal that it's safe to cache the serialized form of `obj` because it won't change during the lifecycle of the `app` or `res` (depending on which `expose()` method is invoked.) The eagerly serialized result is cached to greatly optimize to speed of repeated calls to the `toString()` method. * `[local]`: Optional string name of the "locals" property on which to expose the `obj`. This is used to specify a locals property other than the configured or default (`"state"`) one. * `[namespace]`: Used to specify a `namespace` (described above) when `options` is passed as the second argument to this method. * `[isJSON]`: Optional boolean to signal that the `obj` being serialized is pure JSON data. This allows serialization to take a fast-path making it over 3x faster. **Note:** A `TypeError` will be thrown if a native built-in function is being serialized, like the `Number` constructor. Native built-ins should be called in wrapper functions, which can be serialized. See the [Exposing Functions][] section. See [Exposing Data][] and [Overriding Exposed Values][] for more details. [App Settings]: #app-settings [Express Settings]: http://expressjs.com/api.html#app-settings [Setting a Root Namespace]: #setting-a-root-namespace [Extending an Express App]: #extending-an-express-app [Exposing Data]: #exposing-data [Overriding Exposed Values]: #overriding-exposed-values License ------- This software is free to use under the Yahoo! Inc. BSD license. See the [LICENSE file][] for license text and copyright information. [LICENSE file]: https://github.com/yahoo/express-state/blob/master/LICENSE