Edit Page

Resourceful PubSub (RPS)

Overview

#

For apps that rely heavily on realtime client-server communication—for example, peer-to-peer chat and social networking apps—sending and listening for socket events can quickly become overwhelming. Sails helps smooth away some of the complexity associated with socket events by introducing the concept of resourceful PubSub (Publish / Subscribe). Every model in your app is automatically equipped with resourceful PubSub methods, which provide a conventional, data-centric interface for both broadcasting notifications and subscribing sockets to notifications about individual database records.

If your app is currently using the blueprint API, you are already using resourceful PubSub methods! They are embedded in the default blueprint actions bundled with Sails and are called automatically when those actions run, causing requesting sockets to be subscribed when data is fetched and messages to be broadcasted to already-subscribed sockets when data is changed. (Sockets can be subscribed via a call to .subscribe() or due to a previous socket request to the find or findOne blueprints.)

Even when writing custom code, you can manually call the methods described in this section in lieu of using sails.sockets.* methods directly. Think of resourceful PubSub methods as a way of standardizing the interface for socket communication across your application—these interface elements might be the names of rooms, the schema for data transmitted as socket messages, or the names of socket events. These methods are designed exclusively for scenarios where one or more user interfaces are listening to socket events in order to stay in sync with the backend. If that does not fit your use case or if you are having trouble deciding, don't worry; just call sails.sockets.broadcast(), sails.sockets.join(), or sails.sockets.leave() directly, instead. It is perfectly acceptable to use either approach, or even both approaches in the same app.

Methods

#

Sails exposes three different resourceful PubSub (RPS) methods: .publish(), .subscribe(), and .unsubscribe().

To get a deeper understanding of resourceful PubSub methods, you may find it useful to familiarize yourself with the underlying sails.sockets.* methods first. That's because each RPS method is more or less just a contextualized wrapper around one of the simpler sails.sockets.* methods:

The biggest difference between these methods and their counterparts in sails.sockets.* is that RPS methods expose a higher-level interface. For example, RPS methods choose room names for you behind the scenes, and they infer a conventional event name based on your model's identity.

Listening for events on the client

#

While you are free to use any JavaScript library to listen for socket events on the client, Sails provides its own socket client called sails.io.js as a convenient way to communicate with the Sails server from any web browser or Node.js process that supports Socket.IO. Using the Sails socket client makes listening for resourceful PubSub events as easy as:

io.socket.on('<model identity>', function (msg) {

});

The model identity is typically the lowercased version of the model name, unless it has been manually configured in the model file.

Example

#

Let’s say you have a model named User in your app, with a single “name” attribute. First, we’ll add a listener for “user” events:

io.socket.on('user', function(msg){
  console.log(msg);
})

This will log any notifications that our client socket receives to the console, so long as those socket notifications have "user" as their event name. However, we won’t actually receive those messages until we subscribe this client socket to one or more existing User records (in our server-side code).

If your app has the blueprint API enabled, then subscribing the client socket to the User records is really easy. In addition to fetching data, if the "Find" blueprint action is accessed via a socket request, then it calls User.subscribe() (a resourceful PubSub method) automatically.

For example, imagine you write some client-side code that sends a socket GET request to http://localhost:1337/user:

io.socket.get('/user', function(resData) {
  console.log(resData);
});

When that runs, it will hit the "Find" blueprint action, which returns the current list of users from the Sails server. And if we'd sent a normal HTTP request (like jQuery.get('/user')), then that's all that would happen. But because we sent a socket request, the server also subscribed our client socket to future notifications (calls to .publish()) about the user records that were returned.

See io.socket.get() for more info about using the sails.io.js client to send virtual requests.

Unlike .subscribe(), the RPS .publish() method can run from anywhere—a controller action triggered as the result of a socket request, an AJAX request, or even a cURL request from the command line. Alternatively, .publish() could be called from a custom helper or in a command-line script.

Continuing with the above example, if you were to open an additional browser window and go to the following URL:

/user/create?name=joe

You would see something like the following in the console of the original window:

{
    verb: 'created',
  id: 1,
  data: {
    id: 1,
    name: 'joe',
    createdAt: '2014-08-01T05:50:19.855Z'
    updatedAt: '2014-08-01T05:50:19.855Z'
  }
}

What you're seeing here is a dictionary (aka plain JavaScript object) that was broadcasted by the "Create" blueprint action. In the case of the blueprint API, the format of this data is standardized, but in your app, you can use .publish() to broadcast any data you like.

Is something missing?

If you notice something we've missed or could be improved on, please follow this link and submit a pull request to the sails repo. Once we merge it, the changes will be reflected on the website the next time it is deployed.

Reference

Reference