Feathers: Custom event in hook service not running

Created on 20 Feb 2019  路  11Comments  路  Source: feathersjs/feathers

Steps to reproduce

users.hook.js

const { lowerCase, alterItems } = require('feathers-hooks-common')
const acd = require('../../hooks/acd')

module.exports = {
  before: {
    all: [],
    find: [],
    get: [],
    create: [lowerCase('mail'), acd()],
    update: [lowerCase('mail')],
    patch: [lowerCase('mail')],
    remove: []
  },
...

acd.js

// Use this hook to manipulate incoming or outgoing data.
// For more information on hooks see: http://docs.feathersjs.com/api/hooks.html

// eslint-disable-next-line no-unused-vars
module.exports = function (options = {}) {
  return async context => {
    context.service.emit('customEvent', { id_room: "xi2undj383828823xej3" });
  };
};

channels.js (Authentication disabled only for test purpose)

module.exports = function(app) {
  if(typeof app.channel !== 'function') {
    return;
  }

  app.on('connection', connection => {
    app.channel('anonymous').join(connection);
  });

  app.on('login', (authResult, { connection }) => {
    if(connection) {

      // The connection is no longer anonymous, remove it
      app.channel('anonymous').join(connection);

      // Add it to the authenticated user channel
      app.channel('authenticated').join(connection);

    }
  });

  // eslint-disable-next-line no-unused-vars
  app.publish((data, hook) => {
    return app.channel('anonymous');
    // return app.channel('authenticated');
  });

};

Expected behavior

I expect server emit the custom event to client side, when a new user is created.

Actual behavior

Don't execute emit event in hook service, the client side only receive the added user.

Scripts used in client side, obtained from here:

Modular@feathersjs/client

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/core-js/2.1.4/core.min.js"></script>
<script src="//unpkg.com/@feathersjs/client@^3.0.0/dist/feathers.js"></script>
<script src="//unpkg.com/[email protected]/dist/socket.io.js"></script
// Create user with Webscoket
users.create({
    "email": Math.floor(Math.random() * 109384023)+"[email protected]", //required
    "client_id": "5c6b4066bac35a6658024b1f" //required
})

// Listener created and custom event
 users.on('created', (message) => {
    console.log("New user created: " + message)
})

users.on('customEvent', (message) => {
    console.log("Custom event log: " + message)
})

System configuration

{
  "db": "mongodb",
  "framework": "mongoose"
}

Module versions (especially the part that's not working):

$ npm info @feathersjs/cli version
3.9.0

NodeJS version:

$ node -v
v10.13.0

Module Loader:
@feathersjs/cli

All 11 comments

As documented in the Custom events API, the service also needs to include the custom events it wants to publish to clients in an events array when it is registered.

@daffl you have a example of that?

If I'm not wrong, I need to publish the custom events in channels.js?

The API has an example for a custom service. Existing database adapters use the events option.

Your channel settings will publish all events automatically (but only for the ones that have the events option set).

I understand more! I need use this adapters in my case for example:

In app.js

const service = require('feathers-mongoose');

// Enable Socket.io services
app.configure(socketio());

// Connect to the db, create and register a Feathers service.
app.use('/my-service', service({
  events,  //How put the events here???    <-------------------------
  paginate: {
    default: 10,
    max: 50
  }
}));

Sorry, I'm really confused :anguished:, the events parameter goes like this? :sweat_smile:

const events = [
    service.emit('customEvent', { status: 'completed' }),
    service.emit('otherCustomEvent', { status: 'incomplete' })
]

Really thanks for your help! :grin:

It's an array of event names just like the example of the custom service class:

// Connect to the db, create and register a Feathers service.
app.use('/my-service', service({
  events: [ 'customEvent' ],
  paginate: {
    default: 10,
    max: 50
  }
}));

Now app.service('my-service').emit('customEvent') will be published to all clients in channels that have been configured (anonymous) in your case.

Thanks @daffl ! :blush:

It's an array of event names just like the example of the custom service class:

// Connect to the db, create and register a Feathers service.
app.use('/my-service', service({
  events: [ 'customEvent' ],
  paginate: {
    default: 10,
    max: 50
  }
}));

Now app.service('my-service').emit('customEvent') will be published to all clients in channels that have been configured (anonymous) in your case.

@daffl I try start feathers with this configuration in app.js

const service = require('feathers-mongoose');
const usersModel = require('./models/users.model'); // <---------- Load model

app.use('/users', service({
    usersModel, // <---------------------- Here is the model :(
    events: ['yourTurn']
}));

users.model.js

// users-model.js - A mongoose model
// 
// See http://mongoosejs.com/docs/models.html
// for more of what you can do here.
module.exports = function (app) {
  const mongooseClient = app.get('mongooseClient');
  const { Schema } = mongooseClient;
  const users = new Schema({
    firstname: {
      type: String,
      required: true
    },
    lastname: {
      type: String,
      required: true
    },
    mail: {
      type: String,
      required: true,
      unique: true
    },
    password: {
      type: String,
      required: true,
      select: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    status: {
      connected: {
        type: Boolean,
        default: false
      },
      available: {
        type: Boolean,
        default: false
      }
    },
    client_id: {
      type: mongooseClient.Schema.Types.ObjectId,
      ref: 'accounts',
      required: true
    }

  }, {
    timestamps: true
  });

  return mongooseClient.model('users', users);
};

log

C:\xampp\htdocs\api-feathers\node_modules\feathers-mongoose\lib\service.js:11
      throw new Error('You must provide a Mongoose Model');
      ^

Error: You must provide a Mongoose Model
    at new Service (C:\xampp\htdocs\api-feathers\node_modules\feathers-mongoose\lib\service.js:11:13)
    at init (C:\xampp\htdocs\api-feathers\node_modules\feathers-mongoose\lib\service.js:333:10)
    at Object.<anonymous> (C:\xampp\htdocs\api-feathers\src\app.js:45:19)
    at Module._compile (internal/modules/cjs/loader.js:688:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
    at Module.load (internal/modules/cjs/loader.js:598:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
    at Function.Module._load (internal/modules/cjs/loader.js:529:3)
    at Module.require (internal/modules/cjs/loader.js:636:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (C:\xampp\htdocs\api-feathers\src\index.js:3:13)
    at Module._compile (internal/modules/cjs/loader.js:688:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
    at Module.load (internal/modules/cjs/loader.js:598:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
    at Function.Module._load (internal/modules/cjs/loader.js:529:3)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: `node src/`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging
output above.

What am I doing wrong? :sob: Because I load the model created with CLI feathers generate service

You changed the model property name. The property when initializing the service has to be called Model:

app.use('/users', service({
    Model: usersModel,
    events: ['yourTurn']
}));

You changed the model property name. The property when initializing the service has to be called Model:

app.use('/users', service({
    Model: usersModel,
    events: ['yourTurn']
}));

@daffl sorry, for the stupid error, but this don't resolve the problem :sob:

const service = require('feathers-mongoose');
const usersModel = require('./models/users.model');

app.use('/users', service({
    Model: usersModel,
    events: ['yourTurn']
}));

If I understand, the error say me that the model I required users.model.js is not Moongose Model?

users.model.js

// users-model.js - A mongoose model
// 
// See http://mongoosejs.com/docs/models.html
// for more of what you can do here.

module.exports = function (app) {
  const mongooseClient = app.get('mongooseClient');
  const { Schema } = mongooseClient;
  const users = new Schema({
    firstname: {
      type: String,
      required: true
    },
    lastname: {
      type: String,
      required: true
    },
    // .... Blablabla
  }, {
    timestamps: true
  });

  return mongooseClient.model('users', users);
};

The code above _should_ work. If you are having trouble with this, try regenerating the service (or create a new one) and _only_ add the events: [ 'somethin' ] property in the myservice.service.js file. Don't change anything else.

@daffl perfect, thanks!!!

Add custom event

If use CLI, go to myservice.service.js locted in ./services/myservices/myservice.service.js and in the options variable:

myservice.service.js

const options = {
   Model,
   events: ['customEvent'],
   paginate
};

channels.js

app.service('myservice').emit('customEvent', { data: "customdata" });
Was this page helpful?
0 / 5 - 0 ratings

Related issues

arve0 picture arve0  路  4Comments

ausir0726 picture ausir0726  路  3Comments

codeus-de picture codeus-de  路  4Comments

rrubio picture rrubio  路  4Comments

RickEyre picture RickEyre  路  4Comments