Feathers: Is there a reason why Feathers sends all events to all of its clients by default?

Created on 6 Oct 2016  路  5Comments  路  Source: feathersjs/feathers

I'm trying to understand why Feathers can't automatically ignore the events user didn't subscribe to. From what I understand everything is pretty straightforward.

When we subscribe on an event, the client automatically emits a socketio event, something like this: feathers.io.emit('subscribe', {service, event}). On the server side we catch it and save like this: socket.feathers.subscriptions.push({service, event}). After that we have all the information we need to filter all the events implicitly, sending to the client only relevant data. You just need to add that filter by default to every service.

Is there a reason why you don't do this? Are you planning to implement such a mechanism?

Question

Most helpful comment

@daffl I'm not sure about that. It's always a tradeoff. In my opinion we can go even further and make those subscriptions more granular. In real life in most cases we want to get updates related to a particular document. For example, when the user opens a chat room, he wants to get the updates made in that particular room. So in addition to the service and event fields we could also send a key-value field (something like feathers.io.emit('subscribe', { service: 'messages', event: 'updated', condition: { _id: 'id-of-the-room' } })). So while filtering the events, we could look at a particular field of the updated/created/deleted document and check its value, and based on that decide wether we should send a notification.

It would really make life easier for developers. It's a bit more complicated to implement, but the concept is the same. And all the three levels of granularity may be optional.

All 5 comments

This is indeed a very good question. We have some updates for the filtering mechanism lined up (see https://github.com/feathersjs/feathers/issues/388#issuecomment-239564856) but I like what you are suggesting and unlike #388 I think we might be able to get this into a non-breaking release.

With a subscribe event we could also return some meta information about a service (e.g. if it exists at all and what methods it supports) so Socket clients would finally get a decent error message instead of just a timeout in those cases. If you'd check the subscription in a filter it would also be backwards compatible (just don't register the filter).

Do you think it should be on a per event basis though? I'd probably make it per-service because it would be less to keep track of and in a filter you can just check connection.isSubscribed instead of something like connection.isSubscribed[eventName].

@daffl I'm not sure about that. It's always a tradeoff. In my opinion we can go even further and make those subscriptions more granular. In real life in most cases we want to get updates related to a particular document. For example, when the user opens a chat room, he wants to get the updates made in that particular room. So in addition to the service and event fields we could also send a key-value field (something like feathers.io.emit('subscribe', { service: 'messages', event: 'updated', condition: { _id: 'id-of-the-room' } })). So while filtering the events, we could look at a particular field of the updated/created/deleted document and check its value, and based on that decide wether we should send a notification.

It would really make life easier for developers. It's a bit more complicated to implement, but the concept is the same. And all the three levels of granularity may be optional.

Hi there mates!

I just created something about it on my app, I created my own view controller side with angular 1.x and angular routes, when I get the event I only update user_id screen, or if you are admin or it is an dashboard route, you know what I mean?
feather already does so much! :)

This can now be done pretty nicely with channels:

// server app.js
const feathers = require('@feathersjs/feathers');
const socketio = require('@feathersjs/socketio');

const app = feathers();

app.configure(socketio(io => {
  io.on('connection', socket => {
    socket.on('subscribe', data => {
      const connection = socket.feathers;
      const { event, path } = data;
      const channelName = `${service} ${event}`;

      app.channel(channelName).join(connection);

      app.service(path).publish(event, data => app.channel(channelName));
    });
  }); 
}));

On the client:

const io = require('socket.io-client');
const feathers = require('@feathersjs/feathers');
const socketio = require('@feathersjs/socketio-client');

const socket = io();
const app = feathers();

app.configure(socketio(socket));

app.mixins.push((service, path) => {
  service.mixin({
    on(... args) {
      const event = args[0];

      // If it is a socket client service
      if(service.connection && typeof service.connection.emit === 'function') {
        service.connection.emit('subscribe', {
          path, event
        });
      }

      // Call the old `.on`
      return this._super(... args);
    }
  })
});

Closing this issue but would be happy to help if someone would like to turn this into a plugin 馃槃

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue with a link to this issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

corymsmith picture corymsmith  路  4Comments

RickEyre picture RickEyre  路  4Comments

huytran0605 picture huytran0605  路  3Comments

NetOperatorWibby picture NetOperatorWibby  路  4Comments

harrytang picture harrytang  路  3Comments