Redbone
Backend for your application. Inspired by Redux.
But you can use it with Vuex, or any Flux library.
You can use it with any transport you want, but by default Redbone has only socket.io support.
Install
npm
npm install redbone
yarn
yarn add redbone
Quick start with socket.io
Server side
const Redbone = require('redbone');
const SocketIOConnector = Redbone.connectors.SocketIO;
const connector = new SocketIOConnector(io);
const redbone = new Redbone(connector);
redbone.watch('@@server/user/GET', async function(client, action) {
if (!action.user) throw new Error('User not found');
const user = await Model.getUser(action.user);
if (!user) throw new Error('User not found');
client.dispatch({ '@@user/current/SET', user });
});
redbone.watch('@@server/user/SET', async function(client, action) {
if (!action.user) throw new Error('User is undefined');
const user = await Model.setUser(action.user);
client.dispatch({ type: '@@system/SUCCESS_SAVE', user });
})
redbone.catch((client, action, err) => {
if (action.type === '@@server/user/GET') {
if (err.message === 'User not found') {
return client.dispatch({
type: '@@system/SHOW_ERROR_MODAL',
title: 'User not found'
});
}
}
client.dispatch({
type: '@@system/SHOW_ERROR_MODAL',
title: 'Server Error',
err
});
});
Client side with Redux
After create your store, just add
io.on('dispatch', store.dispatch);
All client.dispatch(action)
at redbone watcher will perform action to client
Watchers
If you want process some of action.type
, you can use redbone.watch
:
redbone.watch(TYPE, fn);
TYPE
— is the action.type
fn
— function to process this TYPE
.
fn
receive 2 params:
client
is a connection to client side, creates by connectoraction
from client with { type: TYPE }
schema.
For quick load folder with watchers you can use readWatchers(dir)
or readWatchersSync(dir)
:
./watchers/user.js
const HttpError = require('redbone/Errors/HttpError');
const db = require('../db');
async load(client, action) {
if (!action.id) throw new HttpError(400, 'User is is not defined');
const user = await db.User.findOne({ id: action.id });
client.dispatch({ type: '@@client/user/SETUP', user });
}
module.exports = [
{ type: "@@server/user/LOAD", action: load }
];
./socket.js
redbone.readWatchersSync(path.join(__dirname, './watchers/'));
Maybe you want use your custom logic for setup several watchers? Ok, just use processWatchers(watchers)
method
Middlewares
Just use use
method of Redbone instance =).
redbone.use((client, action) => {
if (!action.token) throw new HttpError(403, 'Invalid token');
});
If you want stop middleware, just return false
from it:
redbone.use((client, action) => {
if (action.type === '@@server/CONSOLE_LOG') {
console.info(action.log);
return false;
}
});
You want to throw Error? Just do it:
const HttpError = require('redbone/Errors/HttpError');
redbone.use((client, action) => {
if (!action.token) throw new HttpError(403, 'Your token is Invalid');
});
Errors from middlewares and watchers will be caught by a special function, which you can set as follows:
redbone.catch((client, action, err) => {
});
RRPC
RRPC — is Redbone's Remote Procedure Call
You can call any method of any object you want directly from a client.
Add RPC to the Redbone on the server side
const Redbone = require('redbone');
const RPC = Redbone.extensions.RPC;
const redbone = new Redbone(connector);
const rpc = new RPC();
redbone.extension(rpc);
rpc.setLib('mongoose', mongoose.models);
Call from client side with socket.io and default input event
io.emit('dispatch', {
type: '@@server/rpc/CALL',
lib: 'mongoose',
module: 'User',
method: 'getUserAvararLink',
arguments: userToken,
backType: '@@client/user/SET_USER_PROFILE'
});
lib
— library in RPCmodule
— field in librarymethod
— method of fieldarguments
— the first argument of methodflat
— Boolean, if it is true, and arguments is an array, arguments will be send to method with spread operator (...arguments
)merge
— Boolean, if if is true, and the method of module return object — will assign result into the root of action, instead of payload fieldbackType
— type for back action, default is “@@client/rpc/RETURN
”
Publish/Subscribe
Some of your modules can be an instance of EventEmitter
.
If you want to subscribe to some events, you can do it with following action:
io.emit('dispatch', {
type: '@@server/rpc/SUB',
lib: 'mongoose',
module: 'User',
event: 'change_id-1',
payload: userToken,
backType: '@@client/user/SET_USER_PROFILE'
});
Now all change_id-1
events will be dispatched to the client side with backType
If you want to unsubscribe, just use @@server/rpc/UNSUB
type with lib
, module
, event
fields.
All your listeners will be removed automaticaly, when client connection lost.
Other documentation, and grammar fixes comming soon