A Primus integration with hapi (inspired by express.oi and express.io).
- Installation and Configuration
- Authorization
- Raw access to Primus
- Forward primus events to hapi routes
npm install hapi-io --save
server.register({
register: require('hapi-io'),
options: {
...
}
});
connectionLabel
- an optional label to select the connection on which toprimus
- an object which is passed through toPrimus
.auth
- authentication configuration for the socket handshake. Value can be any route auth configuration understood by hapi.
hapi-io can use a hapi auth strategy to authorize a socket.io connection. The socket.io client will not be able to connect if it fails the authentication check.
See options for how to configure.
You can get raw access to the Primus instance as follows:
exports.register = function(server, options, next) {
var primus = server.plugins['hapi-io'].primus;
};
Perfect for exposing HTTP API endpoints over websockets!
Primus events can be mapped to hapi routes; reusing the same authentication, validation, plugins and handler logic.
exports.register = function(server, options, next) {
server.route([
{
method: 'GET',
path: '/users/{id}',
config: {
plugins: {
'hapi-io': 'get-user'
}
},
handler: function(request, reply) {
db.users.get(request.params.id, function(err, user) {
reply(err, user);
});
}
},
{
method: 'POST',
path: '/users',
config: {
plugins: {
'hapi-io': {
event: 'create-user',
mapping: {
headers: ['accept'],
query: ['returnType']
}
}
}
},
handler: function(request, reply) {
db.users.create(request.payload, function(err, user) {
if (err) {
return reply(err).code(201);
}
if (request.headers.accept === 'application/hal+json') {
addMeta(user);
}
if (request.query.returnType !== 'full') {
user = _.omit(user, 'favoriteColor');
}
reply(err, user);
});
}
}
]);
};
var socket = io();
socket.emit('get-user', { id: 'sibartlett'}, function(res) {
// res is the result from the hapi route
});
socket.emit('create-user', {
name: 'Bill Smith',
email: 'blsmith@smithswidgets.com',
location: 'remote',
favoriteColor: 'green',
returnType: 'full'
}, function (res) {
// do something with new user
});
Each time an event is received, a fake HTTP request is created and injected into the hapi server.
The fake HTTP request is constructed as follows:
- The headers and querystring parameters from the socket.io handshake are added to the fake request.
This allows you to use the route's auth stategy - to authenticate the socket.io event.
-
Each field in the event payload is mapped to one of the following hapi param types: headers, path, query or payload. The mapping is determined on a per field basis:
-
If the field is a parameter in the route's path, it's mapped as a path parameter.
-
If the hapi-io config is an object and has a
mapping
property, then the field is checked against the mapping. Allowed mappings are headers, query, and payload. -
If the field exists in the route's validate object, the value is mapped to the corresponding param type.
-
If the route is a 'GET' method, the field is mapped as a query param.
-
Otherwise it's mapped as a payload field.
-
Maps "Authorization" attribute from query or data object if possible and not already mapped.
You can do further processing on a Primus event, after it has been processed by hapi.
You can use the post
option to specify a function, with two parameters: ctx
and next
. ctx
has the following properties:
primus
- the Primus instancespark
- the Primus spark instanceevent
- the Primus eventdata
- the event's data objectreq
- the request object that was injected into hapires
- the result object that was returned by hapiresult
- theres.result
server.route({
method: 'POST',
path: '/rooms/{roomId}/join',
config: {
plugins: {
'hapi-io': {
event: 'join-room',
post: function(ctx, next) {
ctx.spark.join(ctx.data.roomId);
next();
}
}
}
},
...
});