Services
Services
Services are the heart of every Feathers application and JavaScript objects or instances of a class that implement certain methods. Services provide a uniform, protocol independent interface for how to interact with any kind of data like:
- Reading and/or writing from a database
- Interacting with the file system
- Call another API
- Call other services like
- Sending an email
- Processing a payment
- Returning the current weather for a location, etc.
Protocol independent means that to a Feathers service it does not matter if it has been called internally, through a REST API or websockets (both of which we will look at later) or any other way.
Service methods
Service methods are CRUD methods that a service object can implement. Feathers service methods are:
find- Find all data (potentially matching a query)get- Get a single data entry by its unique identifiercreate- Create new dataupdate- Update an existing data entry by completely replacing itpatch- Update one or more data entries by merging with the new dataremove- Remove one or more existing data entries
Below is an example of Feathers service interface as a normal object and a JavaScript class:
const myService = {
async find(params) {
return [];
},
async get(id, params) {},
async create(data, params) {},
async update(id, data, params) {},
async patch(id, data, params) {},
async remove(id, params) {}
}
app.use(‘/my-service’, myService);
{%- language name=”Class”, type=”js” -%}
class myService {
async find(params) {
return [];
}
async get(id, params) {}
async create(data, params) {}
async update(id, data, params) {}
async patch(id, data, params) {}
async remove(id, params) {}
}
app.use(‘/my-service’, new myService());
{%- endcodetabs %}
The parameters for service methods are:
* `id` \- The unique identifier for the data
* `data` \- The data sent by the user (for creating and updating)
* `params` (_optional_) - Additional parameters, for example the authenticated user or the query
> **Note:** A service does not have to implement all those methods but must have at least one.
> **Pro tip:** For more information about service, service methods and parameters see the [Service API documentation](/read/FeathersJS-en/d037).
## A messages service
Now that we know how service methods look like we can implement our own chat message service that allows us to find, create, remove and update messages in-memory. Here we will use a JavaScript class to work with our messages but as we’ve seen above it could also be a normal object.
Below is the complete updated `app.js` with comments:
const feathers = require(‘@feathersjs/feathers’);
class Messages { constructor() { this.messages = []; this.currentId = 0; }
async find(params) { // Return the list of all messages return this.messages; }
async get(id, params) { // Find the message by id const message = this.messages.find(message => message.id === parseInt(id, 10));
// Throw an error if it wasn‘t found
if(!message) {
throw new Error(`Message with id ${id} not found`);
}
// Otherwise return the message
return message;
}
async create(data, params) {
// Create a new object with the original data and an id
// taken from the incrementing currentId counter
const message = Object.assign({
id: ++this.currentId
}, data);
this.messages.push(message);
return message;
}
async patch(id, data, params) { // Get the existing message. Will throw an error if not found const message = await this.get(id);
// Merge the existing message with the new data
// and return the result
return Object.assign(message, data);
}
async remove(id, params) { // Get the message by id (will throw an error if not found) const message = await this.get(id); // Find the index of the message in our message array const index = this.messages.indexOf(message);
// Remove the found message from our array
this.messages.splice(index, 1);
// Return the removed message
return message;
} }
const app = feathers();
// Initialize the messages service by creating // a new instance of our class app.use(‘messages’, new Messages());
## Using services
A service object can be registered on a Feathers application by calling `app.use(path, service)`. `path` will be the name of the service (and the URL if it is exposed as an API which we will learn later).
We can retrieve that service via `app.service(path)` and then call any of its service methods. Add the following to the end of `app.js`:
async function processMessages() { await app.service(‘messages’).create({ text: ‘First message’ });
await app.service(‘messages’).create({ text: ‘Second message’ });
const messageList = await app.service(‘messages’).find();
console.log(‘Available messages’, messageList); }
processMessages();
And run it with
node app.js
We should see this:
Available messages [ { id: 1, text: ‘First message’ }, { id: 2, text: ‘Second message’ } ]
## Service events
When you register a service it will automatically become a [NodeJS EventEmitter](https://nodejs.org/api/events.html) that sends events with the new data when a service method that modifies data (`create`, `update`, `patch` and `remove`) returns. Events can be listened to with `app.service('messages').on('eventName', data => {})`. Here is a list of the service methods and their corresponding events:
Service method | Service event
---|---
`service.create()` | `service.on('created')`
`service.update()` | `service.on('updated')`
`service.patch()` | `service.on('patched')`
`service.remove()` | `service.on('removed')`
We will see later that this is the key to how Feathers enables real-time functionality. For now, let’s update the `processMessages` function in `app.js` as follows:
async function processMessages() { app.service(‘messages’).on(’created‘, message => { console.log(‘Created a new message’, message); });
app.service(‘messages’).on(’removed‘, message => { console.log(‘Deleted message’, message); });
await app.service(‘messages’).create({ text: ‘First message’ });
const lastMessage = await app.service(‘messages’).create({ text: ‘Second message’ });
// Remove the message we just created await app.service(‘messages’).remove(lastMessage.id);
const messageList = await app.service(‘messages’).find();
console.log(‘Available messages’, messageList); }
processMessages();
If we now run the file via
node app.js
We will see how the event handlers are logging the information of created and deleted message like this:
Created a new message { id: 1, text: ‘First message’ } Created a new message { id: 2, text: ‘Second message’ } Deleted message { id: 2, text: ‘Second message’ } Available messages [ { id: 1, text: ‘First message’ } ] ```
What‘s next?
In this chapter we learned about services as Feathers core concept for abstracting data operations. We also saw how a service sends events which we will use later to create real-time applications. First, we will look at Feathers Hooks which is the other key part of how Feathers works.
