
Security News
vlt Launches "reproduce": A New Tool Challenging the Limits of Package Provenance
vlt's new "reproduce" tool verifies npm packages against their source code, outperforming traditional provenance adoption in the JavaScript ecosystem.
Shared REST and real-time APIs with Express.
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
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.
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!"
}
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!" }'
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.
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!
To learn more about Feathers go to the feathersjs.com homepage and continue reading this guide.
FAQs
Build Better APIs, Faster than Ever.
The npm package feathers receives a total of 1,779 weekly downloads. As such, feathers popularity was classified as popular.
We found that feathers demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
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.
Security News
vlt's new "reproduce" tool verifies npm packages against their source code, outperforming traditional provenance adoption in the JavaScript ecosystem.
Research
Security News
Socket researchers uncovered a malicious PyPI package exploiting Deezer’s API to enable coordinated music piracy through API abuse and C2 server control.
Research
The Socket Research Team discovered a malicious npm package, '@ton-wallet/create', stealing cryptocurrency wallet keys from developers and users in the TON ecosystem.