Services are the heart of every Feathers application. A service is simply a JavaScript object that offers one or more of the find, get, create, update, remove and setup service methods and can be used just like an Express middleware with app.use('/path', serviceObject).
A Feathers application with a very simple service and the REST provider set up can look like this:
// app.js
const feathers = require('feathers');
const rest = require('feathers-rest');
const app = feathers();
app.configure(rest());
app.use('/todos', {
get(id, params) {
return Promise.resolve({
id,
params,
description: `You have to do ${id}!`
});
}
});
app.listen(3030);After running
$ npm install feathers feathers-rest
$ node app.js
When goi 8000 ng to localhost:3030/todos/dishes you will see:
{
"id": "dishes",
"description": "You have to do dishes!",
"params": {
"provider": "rest",
"query": {}
}
}Adding query parameters, e.g. localhost:3030/todos/dishes?name=David will return this:
{
"id": "dishes",
"description": "You have to do dishes!",
"params": {
"provider": "rest",
"query": {
"name": "David"
}
}
}When registering a service with app.use('/my-service', myService) Feathers makes a shallow copy of that object and adds its own functionality. This means that to use Feathers functionality (like real-time events, hooks etc.) this object has to be used. It can be retrieved using app.service like this:
const todos = app.service('todos');
// also works with leading/trailing slashes
const todos = app.service('/todos/');
// Now we can use it on the server
todos.get('laundry').then(todo => console.log(todo.description));Important: The original service object will not be modified and will never have any Feathers functionality.
The complete list of service method signatures is as follows:
const myService = {
find(params [, callback]) {},
get(id, params [, callback]) {},
create(data, params [, callback]) {},
update(id, data, params [, callback]) {},
patch(id, data, params [, callback]) {},
remove(id, params [, callback]) {},
setup(app, path) {}
}
app.use('/my-service', myService);Or as an ES6 class:
'use strict';
class MyService {
find(params [, callback]) {}
get(id, params [, callback]) {}
create(data, params [, callback]) {}
update(id, data, params [, callback]) {}
patch(id, data, params [, callback]) {}
remove(id, params [, callback]) {}
setup(app, path) {}
}
app.use('/my-service', new MyService());Service methods should return a Promise and have the following parameters:
idthe identifier for the resource. A resource is the data identified by a unique id.datais the resource dataparamscan contain any extra parameters, for example the authenticated user.params.querycontains the query parameters from the client (see the REST and real-time providers).callbackis an optional callback that can be called instead of returning a Promise. It is a Node-style callback function following thefunction(error, result) {}convention.
These methods basically reflect a CRUD interface:
find(params [, callback])retrieves a list of all resources from the service. Provider parameters will be passed asparams.query.get(id, params [, callback])retrieves a single resource with the givenidfrom the service.create(data, params [, callback])creates a new resource withdata. The method should return a Promise with the newly created data.datamay also be an array which creates and returns a list of resources.update(id, data, params [, callback])replaces the resource identified byidwithdata. The method should return a Promise with the complete updated resource data.idcan also benullwhen updating multiple records.patch(id, data, params [, callback])merges the existing data of the resource identified byidwith the newdata.idcan also benullindicating that multiple resources should be patched. The method should return with the complete updated resource data. Implementpatchadditionally toupdateif you want to separate between partial and full updates and support thePATCHHTTP method.remove(id, params [, callback])removes the resource withid. The method should return a Promise with the removed resource.idcan also benullindicating to delete multiple resources.
setup(app, path) initializes the service, passing an instance of the Feathers application and the path it has been registered on. setup is a great way to connect services:
// app.js
'use strict';
const feathers = require('feathers');
const rest = require('feathers-rest');
class TodoService {
get(id, params) {
return Promise.resolve({
id,
description: `You have to ${id}!`
});
}
}
class MyService {
setup(app) {
this.app = app;
}
get(name, params) {
const todos = this.app.service('todos');
return todos.get('take out trash')
.then(todo => {
return { name, todo };
});
}
}
const app = feathers()
.configure(rest())
.use('/todos', new TodoService())
.use('/my-service', new MyService())
app.listen(8000);You can see the combined response when going to localhost:8000/my-service/test.
Any registered service will automatically turn into an event emitter that emits events when a resource has changed, that is a create, update, patch or remove service call returned successfully. For more information about events, please follow up in the real-time events chapter.