FAQ

We've been collecting some commonly asked questions here. We'll either be updating the guide directly, providing answers here, or both.

How do I debug my app

It's really no different than debugging any other NodeJS app but you can refer to the Debugging section of the guide for more Feathers specific tips and tricks.

Can I expose custom service methods?

Yes and no. You can create custom methods but they won't be exposed over sockets automatically and they won't be mapped to a REST verb (GET, POST, PUT, PATCH, DELETE). See this section for more detail.

I am getting plain text errors with a 500 status code

If you get a plain text error and a 500 status code for errors that should return different status codes, make sure you have feathers-errors/handler configured as described in the error handling chapter.

How can I do custom methods like findOrCreate?

Custom functionality can almost always be mapped to an existing service method using hooks. For example, findOrCreate can be implemented as a before-hook on the service's get method. See this gist for an example of how to implement this in a before-hook.

How do I do nested routes?

Normally we find that they actually aren't needed and that it's much better to keep your routes as flat as possible. However, if the need arises there are a couple different ways. Refer to this section for details.

How do I render templates?

Feathers works just like Express so it's the exact same. We've created a helpful little guide right here.

How do I create channels or rooms

Although Socket.io has a concept of rooms and you can always fall back to it other websocket libraries that Feathers supports do not. The Feathers way of letting a user listen to e.g. messages on a room is through event filtering. There are two ways:

  1. Update the user object with the rooms they are subscribed to and filter based on those
// On the client
function joinRoom(roomId) {
  const user = app.get('user');

  return app.service('users').patch(user.id, { rooms: user.rooms.concat(roomId) });
}

// On the server
app.service('messages').filter(function(message, connection) {
  return connection.user.rooms.indexOf(message.room_id) !== -1;
});

The advantage of this method is that you can show offline/online users that are subscribed to a room.

  1. Create a custom join event with a room id and then filter based on it
app.use(socketio(function(io) {
  io.on('connection', function(socket) {
    socket.on('join', function(roomId) {
      socket.feathers.rooms.push(roomId);
    });
  });
}));

app.service('messages').filter(function(message, connection) {
  return connection.rooms.indexOf(message.room_id) !== -1;
});

The room assignment will persist only for the duration of the socket connection.

I got a possible EventEmitter memory leak detected warning

This warning is not as bad as it sounds. If you got it from Feathers you most likely registered more than 64 services and/or event listeners on a Socket. If you don't think there are that many services or event listeners you may have a memory leak. Otherwise you can increase the number in the Socket.io configuration via io.sockets.setMaxListeners(number) and with Primus via primus.setMaxListeners(number). number can be 0 for unlimited listeners or any other number of how many listeners you'd expect in the worst case.

How do I do validation?

If your database/ORM supports a model or schema (ie. Mongoose or Sequelize) then you have 2 options.

The preferred way

You perform validation at the service level using hooks. This is better because it keeps your app database agnostic so you can easily swap databases without having to change your validations much.

If you write a bunch of small hooks that validate specific things it is easier to test and also slightly more performant because you can exit out of the validation chain early instead of having to go all the way to the point of inserting data into the database to find out if that data is invalid.

If you don't have a model or schema then validating with hooks is currently your only option. If you come up with something different feel free to submit a PR!

The ORM way

With ORM adapters you can perform validation at the model level:

The nice thing about the model level validations is Feathers will return the validation errors to the client in a nice consistent format for you.

Similar to validation, it depends on if your database/ORM supports models or not.

The preferred way

For any of the feathers database/ORM adapters you can just use hooks to fetch data from other services as described here.

This is a better approach because it keeps your application database agnostic and service oriented. By referencing the services (using app.service().find(), etc.) you can still decouple your app and have these services live on entirely separate machines or use entirely different databases without having to change any of your fetching code.

The ORM way

With mongoose you can use the $populate query param to populate nested documents.

// Find Hulk Hogan and include all the messages he sent
app.service('user').find({
  query: {
    name: 'hulk@hogan.net',
    $populate: ['sentMessages']
  }
});

With Sequelize you can do this:

// Find Hulk Hogan and include all the messages he sent
app.service('user').find({
  name: 'hulk@hogan.net',
  sequelize: {
    include: [{
      model: Message,
      where: { sender: Sequelize.col('user.id') }
    }]
  }
});

What about Koa/Hapi/X?

There are many other Node server frameworks out there like Koa, a "next generation web framework for Node.JS" using ES6 generator functions instead of Express middleware or HapiJS etc. Because Feathers 2 is already universally usable we are planning the ability for it to hook into other frameworks on the server as well. More information can be found in this issue.

How do I filter emitted service events?

See this section.

How do I access the request object in hooks or services?

In short, you shouldn't need to. If you look at the hooks chapter you'll see all the params that are available on a hook.

If you still need something from the request object (for example, the requesting IP address) you can simply tack it on to the req.feathers object as described here.

How do I mount sub apps?

It's pretty much exactly the same as Express. There is an example of how to do this in our Examples repository.

How do I do some processing after sending the response to the user?

The hooks workflow allows you to handle these situations quite gracefully. It depends on the promise that you return in your hook. Here's an example of a hook that sends an email, but doesn't wait for a success message.

function (hook) {

  // Send an email by calling to the email service.
  hook.app.service('emails').create({
    to: 'user@email.com',
    body: 'You are so great!'
  });

  // Send a message to some logging service.
  hook.app.service('logging').create(hook.data);

  // Return a resolved promise to immediately move to the next hook
  // and not wait for the two previous promises to resolve.
  return Promise.resolve(hook);
}

results matching ""

    No results matching ""