Skip to content
On this page

Pre-release

You are looking at the website for the fully functional Feathers v5 (Dove) pre-release. Check out what's new, and please let us know about any issues or questions . The current v4 documentation can be found at crow.docs.feathersjs.com.

Services

Services are the heart of every Feathers application. You probably remember the service we made in the quick start to create and find messages. In this chapter we will dive more into services and create a database backed service for our chat messages.

Feathers services

In general, a service is an object or instance of a class that implements certain methods. Services provide a uniform, protocol-independent interface for feathers to interact with any kind of data like:

  • Reading and/or writing to a database
  • Interacting with the file system
  • Calling a third-party API/service like:
    • MailGun for sending emails
    • Stripe for Processing payments
    • OpenWeatherMap for returning the current weather in a location
  • Reading and/or writing to a completely different type of database
  • Anything else you can think of!

This standardized interface allows us to interact with the Database/API/Gnomes inside in a uniform manner across any transport protocol, be it REST, websockets, internally within the application, or Carrier Pigeon 🕊️

Once you write a service method, it can then automatically be used as a REST endpoint or called by a websocket. Feathers will take care of all the boilerplate.

Service methods

Service methods are CRUD methods that a service can implement. Feathers offers a set of general methods that a service can implement, these are:

  • find - Find all data (potentially matching a query)
  • get - Get a single data entry by its unique identifier
  • create - Create new data
  • update - Update an existing data entry by completely replacing it
  • patch - Update one or more data entries by merging with the new data
  • remove - Remove one or more existing data entries
  • setup - Called when the application is started
  • teardown - Called when the application is shut down

Below is an example of Feathers service interface as a class:

ts
import type { Application, Id, NullableId, Params } from '@feathersjs/feathers'

class MyService {
  async find(params: Params) {}
  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) {}
  async setup(path: string, app: Application) {}
  async teardown(path: string, app: Application) {}
}
import type { Application, Id, NullableId, Params } from '@feathersjs/feathers'

class MyService {
  async find(params: Params) {}
  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) {}
  async setup(path: string, app: Application) {}
  async teardown(path: string, app: Application) {}
}
class MyService {
  async find(params) {}
  async get(id, params) {}
  async create(data, params) {}
  async update(id, data, params) {}
  async patch(id, data, params) {}
  async remove(id, params) {}
  async setup(path, app) {}
  async teardown(path, app) {}
}
export {}
class MyService {
  async find(params) {}
  async get(id, params) {}
  async create(data, params) {}
  async update(id, data, params) {}
  async patch(id, data, params) {}
  async remove(id, params) {}
  async setup(path, app) {}
  async teardown(path, app) {}
}
export {}

The parameters for service methods are:

  • id - The unique identifier for the data
  • data - The data sent by the user (for create, update, patch and custom methods)
  • params - Additional parameters, for example the authenticated user or the query

For setup and teardown (which are only called once on application startup and shutdown) we have

Usually those methods can be used for most API functionality but it is also possible to add your own custom service methods.

info

A service does not have to implement all those methods but must have at least one. For more information about services, service methods, and parameters see the Service API documentation.

When used as a REST API, incoming requests get mapped automatically to their corresponding service method like this:

Service methodHTTP methodPath
service.find({ query: {} })GET/messages
service.find({ query: { unread: true } })GET/messages?unread=true
service.get(123)GET/messages/123
service.create(body)POST/messages
service.update(123, body)PUT/messages/123
service.patch(123, body)PATCH/messages/123
service.remove(123)DELETE/messages/123

Registering services

A service can be registered on the Feathers application by calling app.use(name, service[, options]) with a name and the service instance:

ts
import { feathers, type Params } from '@feathersjs/feathers'

class MessageService {
  async get(name: string, params: Params) {
    return {
      message: `You have to do ${name}`
    }
  }
}

type ServiceTypes = {
  messages: MessageService
}

const app = feathers<ServiceTypes>()

// Register the message service on the Feathers application
app.use('messages', new MessageService())
// Or with additional options like which methods should be made available
app.use('messages', new MessageService(), {
  methods: ['get']
})
import { feathers, type Params } from '@feathersjs/feathers'

class MessageService {
  async get(name: string, params: Params) {
    return {
      message: `You have to do ${name}`
    }
  }
}

type ServiceTypes = {
  messages: MessageService
}

const app = feathers<ServiceTypes>()

// Register the message service on the Feathers application
app.use('messages', new MessageService())
// Or with additional options like which methods should be made available
app.use('messages', new MessageService(), {
  methods: ['get']
})
import { feathers } from '@feathersjs/feathers'

class MessageService {
  async get(name, params) {
    return {
      message: `You have to do ${name}`
    }
  }
}

const app = feathers()

// Register the message service on the Feathers application
app.use('messages', new MessageService())
// Or with additional options like which methods should be made available
app.use('messages', new MessageService(), {
  methods: ['get']
})
import { feathers } from '@feathersjs/feathers'

class MessageService {
  async get(name, params) {
    return {
      message: `You have to do ${name}`
    }
  }
}

const app = feathers()

// Register the message service on the Feathers application
app.use('messages', new MessageService())
// Or with additional options like which methods should be made available
app.use('messages', new MessageService(), {
  methods: ['get']
})

To get the service object and use the service methods (and events) we can use app.service(name):

js
const messageService = app.service('messages')
const messages = await messageService.find()
const messageService = app.service('messages')
const messages = await messageService.find()

tip

In a generated application, a service will be registered in the <servicename>.ts|js file.

Service events

A registered service will automatically become a NodeJS EventEmitter 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 methodService event
service.create()service.on('created')
service.update()service.on('updated')
service.patch()service.on('patched')
service.remove()service.on('removed')

This is how Feathers does real-time.

js
app.service('messages').on('created', (data) => {
  console.log('New message created', data)
})
app.service('messages').on('created', (data) => {
  console.log('New message created', data)
})

Database adapters

Now that we have all those service methods, we could go ahead and implement any kind of custom logic using any backend, similar to what we did in the quick start guide. Very often, this means creating, reading, updating and removing data from a database.

Writing all that code yourself for every service is pretty repetitive and cumbersome, which is why Feathers has a collection of pre-built services for different databases. They offer most of the basic functionality and can always be customized to your needs. Feathers database adapters support a common usage API, pagination and querying syntax for many popular databases. The following database adapters are maintained as part of Feathers core:

  • SQL for databases like PostgreSQL, SQLite, MySQL, MariaDB, MSSQL
  • MongoDB for MongoDB
  • Memory for in-memory data

tip

There are also many other community maintained database integrations which you can explore on the ecosystem page. Since they are not part of Feathers core, they are outside the scope of these guides.

If you went with the default selection, we will use SQLite which writes the database to a file and does not require any additional setup. The user service that was created when we generated our application is already using it. If you decide to use another SQL database like PostgreSQL or MySQL, you will need to change the database connection settings in the configuration.

Generating a service

In our newly generated feathers-chat application, we can create database backed services with the following command:

sh
npx feathers generate service
npx feathers generate service

The name for our service is message (this is used for variable names etc.) and for the path we use messages. Anything else we can confirm with the default:

feathers generate service prompts

This is it, we now have a database backed messages service with authentication enabled.

What's next?

In this chapter we learned about services as a 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. After that, we generated a messages service. Next, we will look at Feathers hooks as a way to create middleware for services.

Released under the MIT License.