# Primus Client

Note: We recommend using Feathers and the @feathersjs/primus-client module on the client if possible. To use a direct Primus connection without using Feathers on the client however see the Direct connection section.

# Loading the Primus client library

In the browser the Primus client library (usually at primus/primus.js) always has to be loaded using a <script> tag:

<script type="text/javascript" src="primus/primus.js"></script>

Important: This will make the Primus object globally available. Module loader options are currently not available.

# Client use in NodeJS

In NodeJS a Primus client can be initialized as follows:

const Primus = require('primus');
const Emitter = require('primus-emitter');
const Socket = Primus.createSocket({
  transformer: 'websockets',
  plugin: {
    'emitter': Emitter
  }
});
const socket = new Socket('http://api.feathersjs.com');

# @feathersjs/primus-client

npm version (opens new window) Changelog (opens new window)

npm install @feathersjs/primus-client --save

The @feathersjs/primus-client module allows to connect to services exposed through the Primus server via the configured websocket library.

Important: Primus sockets are also used to call service methods. Using sockets for both, calling methods and receiving real-time events is generally faster than using REST and there is no need to use both, REST and websockets in the same client application at the same time.

# primus(socket)

Initialize the Primus client using a given socket and the default options.

    # primus(socket, options)

    Initialize the Primus client using a given socket and the given options.

    Options can be:

    • timeout (default: 5000ms) - The time after which a method call fails and times out. This usually happens when calling a service or service method that does not exist.
    const feathers = require('@feathersjs/feathers');
    const Primus = require('@feathersjs/primus-client');
    const socket = new Primus('http://api.my-feathers-server.com');
    
    const app = feathers();
    
    app.configure(primus(socket, { timeout: 2000 }));
    

    The timeout per service can be changed like this:

    app.service('messages').timeout = 3000;
    

    # app.primus

    app.primus contains a reference to the socket object passed to primus(socket [, options])

    # Direct connection

    In the browser, the connection can be established by loading the client from primus/primus.js and instantiating a new Primus instance. Unlike HTTP calls, websockets do not have a cross-origin restriction in the browser so it is possible to connect to any Feathers server.

    See the Primus docs (opens new window) for more details.

    ProTip: The socket connection URL has to point to the server root which is where Feathers will set up Primus.

    <script src="primus/primus.js">
    <script>
      var socket = new Primus('http://api.my-feathers-server.com');
    </script>
    

    Service methods can be called by emitting a <servicepath>::<methodname> event with the method parameters. servicepath is the name the service has been registered with (in app.use) without leading or trailing slashes. An optional callback following the function(error, data) Node convention will be called with the result of the method call or any errors that might have occurred.

    params will be set as params.query in the service method call. Other service parameters can be set through a Primus middleware.

    # Authentication

    Sockets will be authenticated automatically by calling .create on the authentication service:

    socket.send('create', 'authentication', {
      strategy: 'local',
      email: 'hello@feathersjs.com',
      password: 'supersecret'
    }, function(error, authResult) {
      console.log(authResult); 
      // authResult will be {"accessToken": "your token", "user": user }
      // You can now send authenticated messages to the server
    });
    

    Important: When a socket disconnects and then reconnects, it has to be authenticated again before making any other request that requires authentication. This is usually done with the jwt strategy using the accessToken from the authResult. The authentication client handles this already automatically.

    # find

    Retrieves a list of all matching resources from the service

    socket.send('find', 'messages', { status: 'read', user: 10 }, (error, data) => {
      console.log('Found all messages', data);
    });
    

    Will call app.service('messages').find({ query: { status: 'read', user: 10 } }) on the server.

    # get

    Retrieve a single resource from the service.

    socket.send('get', 'messages', 1, (error, message) => {
      console.log('Found message', message);
    });
    

    Will call app.service('messages').get(1, {}) on the server.

    socket.send('get', 'messages', 1, { fetch: 'all' }, (error, message) => {
      console.log('Found message', message);
    });
    

    Will call app.service('messages').get(1, { query: { fetch: 'all' } }) on the server.

    # create

    Create a new resource with data which may also be an array.

    socket.send('create', 'messages', {
      text: 'I really have to iron'
    }, (error, message) => {
      console.log('Message created', message);
    });
    

    Will call app.service('messages').create({ "text": "I really have to iron" }, {}) on the server.

    socket.send('create', 'messages', [
      { text: 'I really have to iron' },
      { text: 'Do laundry' }
    ]);
    

    Will call app.service('messages').create on the server with the array.

    # update

    Completely replace a single or multiple resources.

    socket.send('update', 'messages', 2, {
      text: 'I really have to do laundry'
    }, (error, message) => {
      console.log('Message updated', message);
    });
    

    Will call app.service('messages').update(2, { "text": "I really have to do laundry" }, {}) on the server. The id can also be null to update multiple resources:

    socket.send('update', 'messages', null, {
      complete: true
    }, { complete: false });
    

    Will call app.service('messages').update(null, { complete: true }, { query: { complete: false } }) on the server.

    ProTip: update is normally expected to replace an entire resource which is why the database adapters only support patch for multiple records.

    # patch

    Merge the existing data of a single or multiple resources with the new data.

    socket.send('patch', 'messages', 2, {
      read: true
    }, (error, message) => {
      console.log('Patched message', message);
    });
    

    Will call app.service('messages').patch(2, { "read": true }, {}) on the server. The id can also be null to update multiple resources:

    socket.send('patch', 'messages', null, {
      complete: true
    }, {
      complete: false
    }, (error, message) => {
      console.log('Patched message', message);
    });
    

    Will call app.service('messages').patch(null, { complete: true }, { query: { complete: false } }) on the server to change the status for all read app.service('messages').

    # remove

    Remove a single or multiple resources:

    socket.send('remove', 'messages', 2, { cascade: true }, (error, message) => {
      console.log('Removed a message', message);
    });
    

    Will call app.service('messages').remove(2, { query: { cascade: true } }) on the server. The id can also be null to remove multiple resources:

    socket.send('remove', 'messages', null, { read: true });
    

    Will call app.service('messages').remove(null, { query: { read: 'true' } }) on the server to delete all read app.service('messages').

    # Listening to events

    Listening to service events allows real-time behaviour in an application. Service events are sent to the socket in the form of servicepath eventname.

    # created

    The created event will be published with the callback data when a service create returns successfully.

    socket.on('messages created', function(message) {
      console.log('Got a new Message!', message);
    });
    

    # updated, patched

    The updated and patched events will be published with the callback data when a service update or patch method calls back successfully.

    socket.on('my/messages updated', function(message) {
      console.log('Got an updated Message!', message);
    });
    
    socket.send('update', 'my/messages', 1, {
      text: 'Updated text'
    }, {}, function(error, callback) {
     // Do something here
    });
    

    # removed

    The removed event will be published with the callback data when a service remove calls back successfully.

    socket.on('messages removed', function(message) {
      // Remove element showing the Message from the page
      $('#message-' + message.id).remove();
    });
    

    Anything unclear or missing? Get help (opens new window) or Edit this page (opens new window)

    Last Updated: 11/17/2020, 3:17:03 PM