socketcluster-api
v0.3.0
Published
API over SocketCluster's websocket
Downloads
2
Readme
socketcluster-api
SocketCluster-API is a module for creating REST api's over SocketCluster's websocket implementation.
If you're familiar with expressjs using socketcluster-api
will include many familiar steps
This is built using sc-codec-protobuf
which will
encode all messages using Google Protocol Buffer.
All messages are encoded to a protobuf, which also requires you to provided message definitions.
Getting started
Using the following protobuf for the getting started
syntax = "proto3";
package app;
message RequestMessage {
string a = 1;
string b = 2;
}
message ResponseMessage {
string c = 1;
}
message SomeError {
uint32 code = 1;
string message = 2;
}
Server
const protobuf = /* acquire protobuf as a string */
const { API } = require('socketcluster-api');
const app = new API([ protobuf ]
const router = app.router();
// `data` is provided by the client
router.use('/resource', async (data) => {
// ... Perform operations
return {
dataType: '.app.ResponseMessage',
data: { c : 'important result' }
};
// To indicate an error, you could instead throw an object
throw {
dataType: '.app.ResponseMessage',
data: { c : 'important result' }
};
});
// SocketCluster's workerController
function workerController(worker) {
// Get the custom codecEngine so that protobuf message are properly encoded/decoded.
scServer.setCodecEngine(app.codec);
// Register the router for each client that connects
scServer.on('connection', (scSocket) => {
router.register(scSocket);
});
}
Client
import protobuf from /* acquire protobuf as a string */;
import socketCluster from 'socketcluster-client';
import { API } from 'socketcluster-api';
const api = new API([ protobuf ]);
const socket = socketCluster.connect({
codecEngine: api.codec,
port: 8000,
});
// Makes `get` available as a function on `socket`
api.defineEndpoints(socket);
// Calls the `/resource` endpoint, with a message of type `.app.RequestMessage`.
// Note that the data must fit the `.app.RequestMessage` or an error will be thrown.
socket.get('/resource', [ '.app.RequestMessage', { a: 'this string', b: 'this string too' } ])
.then((data) => debug('server replied %o', data))
.catch((err) => debug('got an error:', err));
Advanced topics - Server
Nested routers
const resourceRouter = new Router()
.use(() => { /* handler */ }) // 1
.use('something', () => { /* handler */ }); // 2
const router = new Router()
.use('resource', () => { /* handler */ }) // 3
.use('resource', resourceRouter); // 4
// ...
// This will bind the following routes:
// 1. '/resource/'
// 2. '/resource/something'
// 3. '/resource
// 4. Doesn't bind anything since handler is a `Router`
router.register(scSocket);
NB. /resource
and /resource/
(trailing slash) are different routes and invokes different handlers
Routers can be nested to any depth.