Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

feathers

Package Overview
Dependencies
Maintainers
2
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

feathers

Shared REST and real-time APIs with Express.

  • 1.0.0
  • Source
  • npm
  • Socket score

Version published
Maintainers
2
Created
Source

Feathers - Let your applications fly!

Shared REST and real-time APIs with Express.

To get started

Feathers extends Express 4, one of the most popular web frameworks for NodeJS. It makes it easy to create shared RESTful web services and real-time applications using SocketIO and several other NodeJS websocket libraries.

If you are not familiar with Express head over to the Express Guides to get an idea. Feathers works the exact same way except that var app = require('express')(); is replaced with var app = require('feathers')(). This means that you can literally drop Feathers into your existing Express 4 application and start adding new services right away. The following guide will walk through creating a basic Todo REST and websocket API with Feathers and MongoDB and also explain how to add authentication and authorization. For additional information also make sure to read through the API documentation later.

To get started with this guide, lets create a new folder and in it

npm install feathers

Your first service

The most important concept Feathers adds to Express is that of services. Services can be used just like an Express middleware function but instead are JavaScript objects that provide at least one of the following methods:

var myService = {
  find: function(params, callback) {},
  get: function(id, params, callback) {},
  create: function(data, params, callback) {},
  update: function(id, data, params, callback) {},
  patch: function(id, data, params, callback) {},
  remove: function(id, params, callback) {},
  setup: function(app, path) {}
}

This object can be registered like app.use('/my-service', myService) which - if configured - makes it available as a REST endpoint at /my-service and also through websockets. As usual in NodeJS, callback has to be called with the error (if any) first and the data as the second parameter.

Simple Todo

With those methods available we can implement a very basic Todo service that returns a single Todo using the id passed to the get method:

// app.js
var feathers = require('feathers');
var app = feathers();
var todoService = {
  get: function(id, params, callback) {
    // Call back with no error and the Todo object
    callback(null, {
      id: id,
      text: 'You have to do ' + id + '!'
    });
  }
};

app.configure(feathers.rest())
  .use('/todos', todoService)
  .listen(3000);

After running

node app.js

You can go to localhost:3000/todos/dishes and should see the following JSON response:

{
  "id": "dishes",
  "text": "You have to do dishes!"
}

CRUD Todos

As you might have noticed, service methods mainly reflect basic CRUD functionality. Following up is a longer example with comments for implementing a complete Todo service that manages all Todos in memory:

// todos.js
module.exports = {
  // The current id counter
  id: 0,
  // An array with all todos
  todos: [],

  // Tries to get a single Todo by its id.
  // Throws an error if none can be found.
  getTodo: function(id) {
    var todos = this.todos;

    for(var i = 0; i < todos.length; i++) {
      if(todos[i].id === parseInt(id, 10)) {
        return todos[i];
      }
    }

    // If we didn't return yet we can throw an error
    throw new Error('Could not find Todo');
  },

  // Return all Todos
  find: function(params, callback) {
    callback(null, this.todos);
  },

  // Returns a single Todo by id
  get: function(id, params, callback) {
    try {
      callback(null, this.getTodo(id));
    } catch(error) {
      callback(error);
    }
  },

  // Create a new Todo
  create: function(data, params, callback) {
    // Increment the global ID counter and
    // use it as the Todos id
    data.id = this.id++;
    this.todos.push(data);
    callback(null, data);
  },

  // Update (replace) an existing Todo with new data
  update: function(id, data, params, callback) {
    try {
      var todo = this.getTodo(id);
      var index = this.todos.indexOf(todo);

      data.id = todo.id;
      // Replace all the data
      this.todos[index] = data;
      callback(null, data);
    } catch(error) {
      callback(error);
    }
  },

  // Extend the data of an existing Todo
  patch: function(id, data, params, callback) {
    try {
      var todo = this.getTodo(id);

      // Extend the existing Todo with the new data
      Object.keys(data).forEach(function(key) {
        if(key !== 'id') {
          todo[key] = data[key];
        }
      });

      callback(null, todo);
    } catch(error) {
      callback(error);
    }
  },

  // Remove an existing Todo by id
  remove: function(id, params, callback) {
    try {
      var todo = this.getTodo(id);
      var index = this.todos.indexOf(todo);

      // Splice it out of our Todo list
      this.todos.splice(index, 1);
      callback(null, todo);
    } catch(error) {
      callback(error);
    }
  }
}

The above example exports the service as a module from its own file, todos.js. This means that in app.js we can replace the previous todoService with loading that module. In order to parse JSON encoded HTTP bodies we additionally need to install and load the Express body-parser:

npm install body-parser

// app.js
var feathers = require('feathers');
var bodyParser = require('body-parser');

var app = feathers();
var todoService = require('./todos');

app.configure(feathers.rest())
  .use(bodyParser.json())
  .use('/todos', todoService)
  .listen(3000);

Running app.js will now provide a fully functional REST API at http://localhost:3000/todos. You can test it, for example, using the Postman REST client plugin for Google chrome or via CURL:

curl 'http://localhost:3000/todos/' -H 'Content-Type: application/json' --data-binary '{ "text": "You have to do dishes!" }'

Getting real-time

As previously mentioned, a Feathers service can also be exposed through websockets. You can either use SocketIO or Primus - an abstraction layer for differentNode websocket libraries. In the following examples we will use SocketIO.

SocketIO can be enabled by calling app.configure(feathers.socketio()). Once set up, it is possible to call service methods by emitting events like <servicepath>::<methodname> on the socket and also receive events by listening to <servicepath> <eventname> (eventname can be created, updated, patched or removed). To make it easier to test in a web page, lets also statically host the files in the current folder. app.js then looks like this:

// app.js
var feathers = require('feathers');
var bodyParser = require('body-parser');

var app = feathers();
var todoService = require('./todos');

app.configure(feathers.rest())
  .configure(feathers.socketio())
  .use(bodyParser.json())
  .use('/todos', todoService)
  .use('/', feathers.static(__dirname))
  .listen(3000);

To test the connection, we can create an index.html file in the same folder. The example will connect to SocketIO, create a new Todo and also log when any Todo has been created, updated or patched:

<!DOCTYPE HTML>
<html>
<head>
  <title>Feathers SocketIO example</title>
</head>
<body>
  <h1>A Feathers SocketIO example</h1>
  <script src="http://localhost:3000/socket.io/socket.io.js"></script>
  <script type="text/javascript">
    // Connect to SocketIO on the same host
    var socket = io.connect();

    socket.on('todos created', function(todo) {
      console.log('Someone created a new Todo', todo);
    });

    socket.on('todos updated', function(todo) {
      console.log('Someone updated a Todo', todo);
    });

    socket.on('todos patched', function(todo) {
      console.log('Someone patched', todo);
    });

    socket.emit('todos::create', {
      description: 'You have to do something real-time!'
    }, {}, function(error, todo) {
      socket.emit('todos::find', {}, function(error, todos) {
        console.log('Todos from server:', todos);
      });
    });
  </script>
</body>
</html>

After restarting, going directly to localhost:3000 with the console open will show what is happening on the HTML page. You can also see the newly created Todo at the REST endpoint localhost:3000/todos. With the page open, reating a new Todo via the REST API, for example

curl 'http://localhost:3000/todos/' -H 'Content-Type: application/json' --data-binary '{ "text": "Do something" }'

will also log Someone created a new Todo. This is how you can implement real-time functionality in any web page without a lot of magic using standardized websocket messages instead of having to re-invent your own.

Persisting to MongoDB

Our CRUD Todo functionality implemented in the service is very common and doesn't have to be implemented form scratch every time. In fact, this is almost exactly what is being provided already in the feathers-memory module. Luckily we don't have to stop at storing everything in-memory. For the popular NoSQL database MongoDB , for example, there already is the feathers-mongodb module and if you need more ORM-like functionality through Mongoose you can also use feathers-mongoose.

npm install feathers-mongodb

With a MongoDB instance running locally, we can replace our todoService in app.js with a MongoDB storage on the feathers-demo database and the todos collection like this:

// app.js
var feathers = require('feathers');
var mongodb = require('feathers-mongodb');
var bodyParser = require('body-parser');

var app = feathers();
var todoService = mongodb({
  db: 'feathers-demo',
  collection: 'todos'
});

app.configure(feathers.rest())
  .configure(feathers.socketio())
  .use(bodyParser.json())
  .use('/todos', todoService)
  .use('/', feathers.static(__dirname))
  .listen(3000);

And just like this we have a full REST and real-time Todo API that stores its data into MongoDB in just 16 lines of code!

Next steps

To learn more about Feathers go to the feathersjs.com homepage and continue reading this guide.

Keywords

FAQs

Package last updated on 03 Oct 2014

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc