Services are the heart of every Feathers application. A service is an object or class instance that implements certain methods. Services provide a uniform, protocol-independent interface for reading and writing data.
Service Interface
A service can implement any combination of the following methods:
interface ServiceMethods<Result = any, Data = Partial<Result>, ServiceParams = Params> {
find(params?: ServiceParams & { paginate?: PaginationParams }): Promise<Result | Result[]>
get(id: Id, params?: ServiceParams): Promise<Result>
create(data: Data, params?: ServiceParams): Promise<Result>
update(id: NullableId, data: Data, params?: ServiceParams): Promise<Result | Result[]>
patch(id: NullableId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]>
remove(id: NullableId, params?: ServiceParams): Promise<Result | Result[]>
setup?(app: Application, path: string): Promise<void>
teardown?(app: Application, path: string): Promise<void>
}
Standard Methods
find()
Retrieve a list of resources. Can return paginated or unpaginated results.
find(params?: ServiceParams & { paginate?: PaginationParams }): Promise<Result | Result[]>
Query parameters for filtering, sorting, and pagination
Pagination configuration. Set to false to disable pagination.
result
Result[] | Paginated<Result>
Array of results, or a paginated result object with total, limit, skip, and data properties
// Find all users
const users = await app.service('users').find()
// Find with query
const activeUsers = await app.service('users').find({
query: {
active: true,
$limit: 10,
$skip: 0
}
})
// Paginated result
const result = await app.service('users').find({
query: { $limit: 10 }
})
console.log(result.total) // Total number of records
console.log(result.data) // Array of 10 users
get()
Retrieve a single resource by its unique identifier.
get(id: Id, params?: ServiceParams): Promise<Result>
The unique identifier of the resource (number or string)
// Get user by ID
const user = await app.service('users').get(1)
// Get with additional params
const user = await app.service('users').get(1, {
query: { $select: ['name', 'email'] }
})
create()
Create one or more new resources.
create(data: Data, params?: ServiceParams): Promise<Result>
create(data: Data[], params?: ServiceParams): Promise<Result[]>
The data for the new resource(s). Can be a single object or an array of objects.
// Create a single user
const user = await app.service('users').create({
name: 'John Doe',
email: 'john@example.com'
})
// Create multiple users
const users = await app.service('users').create([
{ name: 'John Doe', email: 'john@example.com' },
{ name: 'Jane Smith', email: 'jane@example.com' }
])
update()
Replace a resource or multiple resources. The update method completely replaces the resource(s).
update(id: Id, data: Data, params?: ServiceParams): Promise<Result>
update(id: null, data: Data, params?: ServiceParams): Promise<Result[]>
The unique identifier of the resource. Use null to update multiple resources.
The complete new data for the resource(s)
// Update a single user (replaces entire object)
const user = await app.service('users').update(1, {
name: 'John Updated',
email: 'john.updated@example.com',
active: true
})
// Update multiple users
const users = await app.service('users').update(null,
{ active: false },
{ query: { verified: false } }
)
patch()
Merge updates into a resource or multiple resources. Unlike update, patch only modifies the provided fields.
patch(id: Id, data: PatchData, params?: ServiceParams): Promise<Result>
patch(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>
The unique identifier of the resource. Use null to patch multiple resources.
Partial data to merge into the resource(s)
// Patch a single user (only updates provided fields)
const user = await app.service('users').patch(1, {
active: true
})
// Patch multiple users
const users = await app.service('users').patch(null,
{ verified: true },
{ query: { email: { $like: '%@example.com' } } }
)
remove()
Remove a resource or multiple resources.
remove(id: Id, params?: ServiceParams): Promise<Result>
remove(id: null, params?: ServiceParams): Promise<Result[]>
The unique identifier of the resource. Use null to remove multiple resources.
// Remove a single user
const removedUser = await app.service('users').remove(1)
// Remove multiple users
const removedUsers = await app.service('users').remove(null, {
query: { active: false }
})
Lifecycle Methods
setup()
Called when the application is started. Use this to initialize connections, load data, etc.
setup?(app: Application, path: string): Promise<void>
The Feathers application instance
The path where this service is registered
class MyService {
async setup(app, path) {
console.log(`Setting up service at ${path}`)
// Initialize database connection, load cache, etc.
}
async find(params) {
return []
}
}
teardown()
Called when the application is shut down. Use this to close connections, clean up resources, etc.
teardown?(app: Application, path: string): Promise<void>
The Feathers application instance
The path where this service is registered
class MyService {
async teardown(app, path) {
console.log(`Tearing down service at ${path}`)
// Close database connection, flush cache, etc.
}
async find(params) {
return []
}
}
Service Parameters
Params
The params object contains metadata about the service call:
interface Params<Q = Query> {
query?: Q
provider?: string
route?: { [key: string]: any }
headers?: { [key: string]: any }
// ... custom properties
}
Query parameters for filtering and pagination
The transport that made the service call (e.g., 'rest', 'socketio', undefined for internal calls)
Route parameters from the URL path
HTTP headers from the request
class UserService {
async find(params) {
const { query, provider, user } = params
// Internal call (no provider)
if (!provider) {
// Return all users
}
// External call
// Apply security restrictions
}
}
Service Options
When registering a service, you can pass options:
interface ServiceOptions {
events?: string[]
methods?: string[]
serviceEvents?: string[]
routeParams?: { [key: string]: any }
}
Custom events that this service emits to clients (merged with default events)
Service methods that should be available externally to clients
Full list of events this service emits (replaces default events)
Initial data to always add as route params to this service
app.use('/messages', messageService, {
methods: ['find', 'get', 'create'],
events: ['typing', 'delivered'],
routeParams: {
appId: 'my-app'
}
})
Custom Service Methods
Services can have custom methods in addition to the standard CRUD methods:
class UserService {
async find(params) {
return []
}
async resetPassword(data, params) {
const { email } = data
// Send password reset email
return { message: 'Password reset email sent' }
}
}
app.use('/users', new UserService(), {
methods: ['find', 'resetPassword']
})
// Call custom method
await app.service('users').resetPassword({ email: 'user@example.com' })
Protected Method Names
The following method names are reserved and cannot be used as custom methods:
- All methods from
Object.prototype and EventEmitter.prototype
all, around, before, after, error
hooks, setup, teardown, publish
Example Service
import { Id, Params } from '@feathersjs/feathers'
interface User {
id: Id
name: string
email: string
active: boolean
}
class UserService {
private users: User[] = []
private currentId = 0
async setup(app, path) {
console.log(`UserService registered at ${path}`)
}
async find(params?: Params) {
const { query = {} } = params || {}
let result = this.users
if (query.active !== undefined) {
result = result.filter(u => u.active === query.active)
}
return result
}
async get(id: Id, params?: Params) {
const user = this.users.find(u => u.id === id)
if (!user) {
throw new Error(`User ${id} not found`)
}
return user
}
async create(data: Partial<User>, params?: Params) {
const user: User = {
id: ++this.currentId,
name: data.name!,
email: data.email!,
active: data.active ?? true
}
this.users.push(user)
return user
}
async patch(id: Id, data: Partial<User>, params?: Params) {
const user = await this.get(id)
Object.assign(user, data)
return user
}
async remove(id: Id, params?: Params) {
const index = this.users.findIndex(u => u.id === id)
if (index === -1) {
throw new Error(`User ${id} not found`)
}
return this.users.splice(index, 1)[0]
}
async teardown(app, path) {
console.log(`UserService at ${path} shutting down`)
}
}
app.use('/users', new UserService())