nexus-flux-rest
Version:
Nexus Flux REST ===============
123 lines (103 loc) • 3.32 kB
Markdown
Nexus Flux REST
===============
Nexus Flux for REST backends. Stores are exposed by HTTP GET, and Actions are exposed by HTTP POST.
This package implements flux over the wire without the real-time websocket automatic updates.
If you want a more complex stack but automatic updates, you should check out [nexus-flux-socket.io](https://github.com/elierotenberg/nexus-flux-socket.io).
If you want to use Nexus Flux (including Nexus Flux REST) in a React app, you should also check out [react-nexus](https://github.com/elierotenberg/react-nexus).
Example
=======
Backend code (run by a Node server in our datacenter):
```js
import RESTServer from 'nexus-flux-rest/server';
// We define the behaviour of the server-side single source of truth
class MyServer extends RESTServer {
constructor() {
super({ port: 8080, salt: '--INSERT UNIQUE SALT--' });
this.stores = {
'/counters': new Remutable({
visits: 0,
clicks: 0,
mouseenter: 0,
mouseleave: 0,
}),
};
}
serveStore({ path }) {
return Promise.try(() => {
if(!_.isString(path)) {
throw createError(400, 'Path should be a string.');
}
if(this.stores[path] === void 0) {
throw createError(404, 'No such store.');
}
return this.stores[path].toJSON();
});
}
dispatchAction(path, params) {
return Promise.try(() => {
if(path === '/increaseCounter') {
const { target } = params;
if(target === 'visits' ||
target === 'clicks' ||
target === 'mouseenter' ||
target === 'mouseleave') {
this.dispatchUpdate('/counters',
this.stores['/counters']
.set(target, this.stores['/counters'].get(target) + 1)
.commit()
);
}
}
});
}
}
```
Front-end code (run by either client browser or a Node server for server-side rendering):
```
import { root, component } from 'react-nexus';
// Root component
class MyRoot extends React.Component { ... }
// Regular component
class Counter extends React.Component {
static propTypes = {
target: React.PropTypes.string.isRequired,
counter: React.PropTypes.number.isRequired,
};
render() {
const { props } = this;
return <span>{target}: {counter}</span>;
}
}
class Button extends React.Component {
componentDidMount() {
this.increaseCounter('visits')();
}
increaseCounter(target) {
return (e) => {
if(e) {
e.preventDefault();
}
this.props.nexus.dispatchAction('/increaseCounter', { target: target });
};
}
render() {
return <button
onClick={this.increaseCounter('clicks')}
onMouseEnter={this.increaseCounter('mouseenter')}
onMouseLeave={this.increaseCounter('mouseleave')}
>Click me!</button>;
}
}
```
#### License
MIT [Elie Rotenberg](http://elie.rotenberg.io) <[elie@rotenberg.io](mailto:elie@rotenberg.io)>