"Services" are the heart of every Feathers application. Services are JavaScript objects (or instances of ES6 classes) that implement certain methods. Feathers itself will also add some additional methods and functionality to its services.
Service methods are pre-defined CRUD methods that your service object can implement (or that have already been implemented by one of the database adapters). Below is an example of a Feathers service using async/await as a JavaScript object and a JavaScript or Typescript class:
:::: tabs :options="{ useUrlFragment: false }"
::: tab "Object"
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) {},
setup(app, path) {}
}
app.use('/my-service', myService);
:::
::: tab "Class(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) {}
setup(app, path) {}
}
app.use('/my-service', new MyService());
:::
::: tab "Class(TS)"
import { ServiceMethods, Params, Id, NullableId } from "@feathersjs/feathers";
import { Application } from "../../declarations";
class MyService implements ServiceMethods<any> {
async find(params: Params) {
return [];
}
async get(id: Id, params: Params) {}
async create(data: any, params: Params) {}
async update(id: NullableId, data: any, params: Params) {}
async patch(id: NullableId, data: any, params: Params) {}
async remove(id: NullableId, params: Params) {}
setup(app: Application, path: string) {}
}
app.use('/my-service', new MyService());
:::
::::
ProTip: Methods are optional, and if a method is not implemented Feathers will automatically emit a
NotImplemented
error. At least one of the methods (e.g.setup
) must be implemented to be considered a service.
ProTip: Notice that the TypeScript version of the example
MyService
class implements theServiceMethods
interface. If you look at, for instance, the users service that the Feathers CLI generates for you when you scaffold a new Feathers application you will notice that the users service class extends the chosen database adapter service class. The database adapter service classes actually extend a class namedAdapterService
, which implements theServiceMethods
interface.
Important: Always use the service returned by
app.service(path)
not the service object (themyService
object above) directly. See the app.service documentation for more information.
Service methods must use async/await or return a Promise
and have the following parameters:
id
— The identifier for the resource. A resource is the data identified by a unique id.data
— The resource data.params
- Additional parameters for the method call (see params)
Once registered, the service can be retrieved and used via app.service():
const myService = app.service('my-service');
const items = await myService.find();
const item = await app.service('my-service').get(1);
console.log('.get(1)', item);
Note: Although probably the most common use case, a service does not necessarily have to connect to a database. A custom service can implement any functionality like talking to another API or send an email etc.
Important: This section describes the general usage of service methods and how to implement them. They are already implemented by the official Feathers database adapters. For specifics on how to use the database adapters, see the database adapters common API.
params
contain additional information for the service method call. Some properties in params
can be set by Feathers already. Commonly used are:
params.query
- the query parameters from the client, either passed as URL query parameters (see the REST chapter) or through websockets (see Socket.io or Primus).params.provider
- The transport (rest
,socketio
orprimus
) used for this service call. Will beundefined
for internal calls from the server (unless passed explicitly).params.authentication
- The authentication information to use for the authentication serviceparams.user
- The authenticated user, either set by Feathers authentication or passed explicitly.params.connection
- If the service call has been made by a real-time transport (e.g. through websockets),params.connection
is the connection object that can be used with channels.
Important: For external calls only
params.query
will be sent between the client and server. If not passed,params.query
will beundefined
for internal calls.
service.find(params) -> Promise
- Retrieves a list of all resources from the service. params.query
can be used to filter and limit the returned data.
app.use('/messages', {
async find(params) {
return [{
id: 1,
text: 'Message 1'
}, {
id: 2,
text: 'Message 2'
}];
}
});
Note:
find
does not have to return an array; it can also return an object. The database adapters already do this for pagination.
service.get(id, params) -> Promise
- Retrieves a single resource with the given id
from the service.
app.use('/messages', {
async get(id, params) {
return {
id,
text: `You have to do ${id}!`
};
}
});
service.create(data, params) -> Promise
- Creates a new resource with data
. The method should return with the newly created data. data
may also be an array.
app.use('/messages', {
messages: [],
async create(data, params) {
this.messages.push(data);
return data;
}
});
Important: A successful
create
method call emits thecreated
service event.
Note: With a database adapters
data
can be an array but themulti
option has to be set.
service.update(id, data, params) -> Promise
- Replaces the resource identified by id
with data
. The method should return with the complete, updated resource data. id
can also be null
when updating multiple records, with params.query
containing the query criteria.
Important: A successful
update
method call emits theupdated
service event.
Note: The database adapters do not support completely replacing multiple entries.
patch(id, data, params) -> Promise
- Merges the existing data of the resource identified by id
with the new data
. id
can also be null
indicating that multiple resources should be patched with params.query
containing the query criteria.
Note: With a database adapters the
multi
option has to be set explicitly to support patching multiple entries.
The method should return with the complete, updated resource data. Implement patch
additionally (or instead of) update
if you want to distinguish between partial and full updates and support the PATCH
HTTP method.
Important: A successful
patch
method call emits thepatched
service event.
service.remove(id, params) -> Promise
- Removes the resource with id
. The method should return with the removed data. id
can also be null
, which indicates the deletion of multiple resources, with params.query
containing the query criteria.
Important: A successful
remove
method call emits theremoved
service event.
Note: With a database adapters the
multi
option has to be set explicitly to support removing multiple entries.
service.setup(app, path) -> Promise
is a special method that initializes the service, passing an instance of the Feathers application and the path it has been registered on.
For services registered before app.listen
is invoked, the setup
function of each registered service is called on invoking app.listen
. For services registered after app.listen
is invoked, setup
is called automatically by Feathers when a service is registered.
setup
is a great place to initialize your service with any special configuration or if connecting services that are very tightly coupled (see below).
const feathers = require('@feathersjs/feathers');
const { rest } = require('@feathersjs/express');
class MessageService {
async get(id, params) {
return {
id,
read: false,
text: `Feathers is great!`,
createdAt: new Date.getTime()
};
}
}
class MyService {
setup(app) {
this.app = app;
}
async get(name, params) {
const messages = this.app.service('messages');
const message = await messages.get(1, params);
return { name, message };
}
}
const app = feathers()
.configure(rest())
.use('/messages', new MessageService())
.use('/my-service', new MyService())
app.listen(3030);
When registering a service, Feathers (or its plugins) can also add its own methods to a service. Most notably, every service will automatically become an instance of a NodeJS EventEmitter.
Register hooks for this service.
Register an event publishing callback. For more information, see the channels chapter.
service.mixin(mixin) -> service
extends the functionality of a service. For more information see the Uberproto project page.
Provided by the core NodeJS EventEmitter .on. Registers a listener
method (function(data) {}
) for the given eventname
.
Important: For more information about service events, see the Events chapter.
Provided by the core NodeJS EventEmitter .emit. Emits the event eventname
to all event listeners.
Important: For more information about service events, see the Events chapter.
Provided by the core NodeJS EventEmitter .removeListener. Removes all listeners, or the given listener, for eventname
.
Note: For more information about service events, see the Events chapter.