Real-time APIs

In the services chapter we saw that Feathers services automatically send created, updated, patched and removed events when a create, update, patch or remove service method returns. Real-time means that those events are also published to connected clients so that they can react accordingly, e.g. update their UI.

To allow real-time communication with clients we need a transport that supports bi-directional communication. In Feathers those are the Socket.io and Primus transport both of which use websockets to receive real-time events and also call service methods.

Important: The REST transport does not support real-time updates. Since socket transports also allow to call service methods and generally perform better, we recommend using a real-time transport whenever possible.

In this chapter we will use Socket.io and create a database backed real-time API that also still supports a REST endpoint.

Using the transport

After installing

  1. npm install @feathersjs/socketio --save

The Socket.io transport can be configured and used with a standard configuration like this:

  1. const feathers = require('@feathersjs/feathers');
  2. const socketio = require('@feathersjs/socketio');
  3. // Create a Feathers application
  4. const app = feathers();
  5. // Configure the Socket.io transport
  6. app.configure(socketio());
  7. // Start the server on port 3030
  8. app.listen(3030);

It also works in combination with a REST API setup:

  1. const feathers = require('@feathersjs/feathers');
  2. const express = require('@feathersjs/express');
  3. const socketio = require('@feathersjs/socketio');
  4. // This creates an app that is both, an Express and Feathers app
  5. const app = express(feathers());
  6. // Turn on JSON body parsing for REST services
  7. app.use(express.json())
  8. // Turn on URL-encoded body parsing for REST services
  9. app.use(express.urlencoded({ extended: true }));
  10. // Set up REST transport using Express
  11. app.configure(express.rest());
  12. // Configure the Socket.io transport
  13. app.configure(socketio());
  14. // Set up an error handler that gives us nicer errors
  15. app.use(express.errorHandler());
  16. // Start the server on port 3030
  17. app.listen(3030);

Channels

Channels determine which real-time events should be sent to which client. For example, we might want to only send messages to authenticated users or users in the same room. For this example however, we will just enable real-time functionality for all connections:

  1. // On any real-time connection, add it to the `everybody` channel
  2. app.on('connection', connection => app.channel('everybody').join(connection));
  3. // Publish all events to the `everybody` channel
  4. app.publish(() => app.channel('everybody'));

Note: More information about channels can be found in the channel API documentation.

A messages API

Putting it all together, our REST and real-time API with a messages service app.js looks like this:

  1. const feathers = require('@feathersjs/feathers');
  2. const express = require('@feathersjs/express');
  3. const socketio = require('@feathersjs/socketio');
  4. const memory = require('feathers-memory');
  5. // This creates an app that is both, an Express and Feathers app
  6. const app = express(feathers());
  7. // Turn on JSON body parsing for REST services
  8. app.use(express.json())
  9. // Turn on URL-encoded body parsing for REST services
  10. app.use(express.urlencoded({ extended: true }));
  11. // Set up REST transport using Express
  12. app.configure(express.rest());
  13. // Configure the Socket.io transport
  14. app.configure(socketio());
  15. // On any real-time connection, add it to the `everybody` channel
  16. app.on('connection', connection => app.channel('everybody').join(connection));
  17. // Publish all events to the `everybody` channel
  18. app.publish(() => app.channel('everybody'));
  19. // Initialize the messages service
  20. app.use('messages', memory({
  21. paginate: {
  22. default: 10,
  23. max: 25
  24. }
  25. }));
  26. // Set up an error handler that gives us nicer errors
  27. app.use(express.errorHandler());
  28. // Start the server on port 3030
  29. const server = app.listen(3030);
  30. server.on('listening', () => console.log('Feathers API started at localhost:3030'));

As always, we can start our server again by running

  1. node app.js

Using the API

The real-time API can be used by establishing a websocket connection. For that we need the Socket.io client which we can included by updating public/index.html to:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Feathers Basics</title>
  6. </head>
  7. <body>
  8. <h1>Welcome to Feathers</h1>
  9. <p>Open up the console in your browser.</p>
  10. <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
  11. <script type="text/javascript" src="//unpkg.com/@feathersjs/client@^3.0.0/dist/feathers.js"></script>
  12. <script type="text/javascript" src="//unpkg.com/feathers-memory@^2.0.0/dist/feathers-memory.js"></script>
  13. <script src="client.js"></script>
  14. </body>
  15. </html>

Then we can initialize and use the socket directly making some calls and listening to real-time events by updating public/client.js to this:

  1. /* global io */
  2. // Create a websocket connecting to our Feathers server
  3. const socket = io('http://localhost:3030');
  4. // Listen to new messages being created
  5. socket.on('messages created', message =>
  6. console.log('Someone created a message', message)
  7. );
  8. socket.emit('create', 'messages', {
  9. text: 'Hello from socket'
  10. }, (error, result) => {
  11. if (error) throw error
  12. socket.emit('find', 'messages', (error, messageList) => {
  13. if (error) throw error
  14. console.log('Current messages', messageList);
  15. });
  16. });

What’s next?

In this chapter we added the Socket.io transport and saw how to use channels to send events from server to client. In the next chapter we will look at how to use the browser Feathers application and client services to handle these events easily.