Skip to content
On this page

Service classes

The <service>.class file exports the service class or object.

Database services

When using a database, the service class will be extended from the Feathers database adapter service. Like any class, existing methods can be overriden or you can add your own methods (which can also be made available externally as custom methods when registering the service).

Note

The generic types for a database service are always AdapterService<MessageType, DataType, ParamsType, PatchType>. The MessageService<ServiceParams extends Params = MessageParams> generic is used to change the parameter type when using this service interface as a client side service.

Overriding methods

When overriding an existing service method on a database adapter the method and overload signatures have to match. The following example shows how to override every service method. Only the methods you want to customize have to be added.

The SQL Knex service methods can be customized like this:

ts
import { Id, NullableId, Paginated } from '@feathersjs/feathers'

export interface MessageParams extends KnexAdapterParams<MessageQuery> {}

// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService<
  ServiceParams extends Params = MessageParams
> extends KnexService<Message, MessageData, MessageParams, MessagePatch> {
  async find(
    params?: MessageParams & { paginate?: { default?: number; max?: number } }
  ): Promise<Paginated<Message>>
  async find(params?: ServiceParams & { paginate: false }): Promise<Message[]>
  async find(params?: ServiceParams): Promise<Paginated<Message> | Message[]>
  async find(params?: ServiceParams): Promise<Paginated<Message> | Message[]> {
    return super.find(params)
  }

  async get(id: Id, params?: ServiceParams): Promise<Message> {
    return super.get(id, params)
  }

  async create(data: MessageData, params?: ServiceParams): Promise<Message>
  async create(data: MessageData[], params?: ServiceParams): Promise<Message[]>
  async create(
    data: MessageData | MessageData[],
    params?: ServiceParams
  ): Promise<Message | Message[]> {
    return super.create(data, params)
  }

  async update(id: Id, data: Data, params?: ServiceParams): Promise<Message> {
    return super.update(id, data, params)
  }

  async patch(id: Id, data: MessagePatch, params?: ServiceParams): Promise<Message>
  async patch(id: null, data: MessagePatch, params?: ServiceParams): Promise<Message[]>
  async patch(
    id: NullableId,
    data: MessagePatch,
    params?: ServiceParams
  ): Promise<Message | Message[]> {
    return super.patch(id, data, params)
  }

  async remove(id: Id, params?: ServiceParams): Promise<Message>
  async remove(id: null, params?: ServiceParams): Promise<Message[]>
  async remove(id: NullableId, params?: ServiceParams): Promise<Message | Message[]> {
    return super.remove(id, params)
  }
}
import { Id, NullableId, Paginated } from '@feathersjs/feathers'

export interface MessageParams extends KnexAdapterParams<MessageQuery> {}

// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService<
  ServiceParams extends Params = MessageParams
> extends KnexService<Message, MessageData, MessageParams, MessagePatch> {
  async find(
    params?: MessageParams & { paginate?: { default?: number; max?: number } }
  ): Promise<Paginated<Message>>
  async find(params?: ServiceParams & { paginate: false }): Promise<Message[]>
  async find(params?: ServiceParams): Promise<Paginated<Message> | Message[]>
  async find(params?: ServiceParams): Promise<Paginated<Message> | Message[]> {
    return super.find(params)
  }

  async get(id: Id, params?: ServiceParams): Promise<Message> {
    return super.get(id, params)
  }

  async create(data: MessageData, params?: ServiceParams): Promise<Message>
  async create(data: MessageData[], params?: ServiceParams): Promise<Message[]>
  async create(
    data: MessageData | MessageData[],
    params?: ServiceParams
  ): Promise<Message | Message[]> {
    return super.create(data, params)
  }

  async update(id: Id, data: Data, params?: ServiceParams): Promise<Message> {
    return super.update(id, data, params)
  }

  async patch(id: Id, data: MessagePatch, params?: ServiceParams): Promise<Message>
  async patch(id: null, data: MessagePatch, params?: ServiceParams): Promise<Message[]>
  async patch(
    id: NullableId,
    data: MessagePatch,
    params?: ServiceParams
  ): Promise<Message | Message[]> {
    return super.patch(id, data, params)
  }

  async remove(id: Id, params?: ServiceParams): Promise<Message>
  async remove(id: null, params?: ServiceParams): Promise<Message[]>
  async remove(id: NullableId, params?: ServiceParams): Promise<Message | Message[]> {
    return super.remove(id, params)
  }
}
import { Id, NullableId, Paginated } from '@feathersjs/feathers'

// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService extends KnexService {
  async find(params) {
    return super.find(params)
  }

  async get(id, params) {
    return super.get(id, params)
  }
  async create(data, params) {
    return super.create(data, params)
  }

  async update(id, data, params) {
    return super.update(id, data, params)
  }
  async patch(id, data, params) {
    return super.patch(id, data, params)
  }
  async remove(id, params) {
    return super.remove(id, params)
  }
}
import { Id, NullableId, Paginated } from '@feathersjs/feathers'

// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService extends KnexService {
  async find(params) {
    return super.find(params)
  }

  async get(id, params) {
    return super.get(id, params)
  }
  async create(data, params) {
    return super.create(data, params)
  }

  async update(id, data, params) {
    return super.update(id, data, params)
  }
  async patch(id, data, params) {
    return super.patch(id, data, params)
  }
  async remove(id, params) {
    return super.remove(id, params)
  }
}

Other service methods

It is also possible to write your own service methods where the signatures don't have to match by extending from the KnexAdapter (instead of the KnexService) class. It does not have any of the service methods implemented but you can use the internal _find, _get, _update, _patch and _remove adapter methods to work with the database and implement the service method in the way you need.

ts
import { Id } from '@feathersjs/feathers'
import { KnexAdapter } from '@feathersjs/knex'

export interface MessageParams extends KnexAdapterParams<MessageQuery> {}

// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService<
  ServiceParams extends Params = MessageParams
> extends KnexAdapter<Message, MessageData, MessageParams, MessagePatch> {
  async find(params: ServiceParams) {
    const page = this._find(params)

    return {
      status: 'ok',
      ...page
    }
  }

  async get(id: Id, params: ServiceParams) {
    return {
      message: `Hello ${id}`
    }
  }
}
import { Id } from '@feathersjs/feathers'
import { KnexAdapter } from '@feathersjs/knex'

export interface MessageParams extends KnexAdapterParams<MessageQuery> {}

// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService<
  ServiceParams extends Params = MessageParams
> extends KnexAdapter<Message, MessageData, MessageParams, MessagePatch> {
  async find(params: ServiceParams) {
    const page = this._find(params)

    return {
      status: 'ok',
      ...page
    }
  }

  async get(id: Id, params: ServiceParams) {
    return {
      message: `Hello ${id}`
    }
  }
}
import { Id } from '@feathersjs/feathers'
import { KnexAdapter } from '@feathersjs/knex'

// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService extends KnexAdapter {
  async find(params) {
    const page = this._find(params)

    return {
      status: 'ok',
      ...page
    }
  }

  async get(id, params) {
    return {
      message: `Hello ${id}`
    }
  }
}
import { Id } from '@feathersjs/feathers'
import { KnexAdapter } from '@feathersjs/knex'

// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService extends KnexAdapter {
  async find(params) {
    const page = this._find(params)

    return {
      status: 'ok',
      ...page
    }
  }

  async get(id, params) {
    return {
      message: `Hello ${id}`
    }
  }
}

Custom methods

Custom service methods can be added to an SQL Knex service as follows:

ts
export interface MessageParams extends KnexAdapterParams<MessageQuery> {}

export type MyMethodData = { greeting: string }

// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService<
  ServiceParams extends Params = MessageParams
> extends KnexService<Message, MessageData, MessageParams, MessagePatch> {
  async myMethod(data: MyMethodData, params: ServiceParams) {
    return {
      message: `${data.greeting || 'Hello'} ${params.user.name}!`
    }
  }
}
export interface MessageParams extends KnexAdapterParams<MessageQuery> {}

export type MyMethodData = { greeting: string }

// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService<
  ServiceParams extends Params = MessageParams
> extends KnexService<Message, MessageData, MessageParams, MessagePatch> {
  async myMethod(data: MyMethodData, params: ServiceParams) {
    return {
      message: `${data.greeting || 'Hello'} ${params.user.name}!`
    }
  }
}
// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService extends KnexService {
  async myMethod(data, params) {
    return {
      message: `${data.greeting || 'Hello'} ${params.user.name}!`
    }
  }
}
// By default calls the standard Knex adapter service methods but can be customized with your own functionality.
export class MessageService extends KnexService {
  async myMethod(data, params) {
    return {
      message: `${data.greeting || 'Hello'} ${params.user.name}!`
    }
  }
}

Custom services

As shown in the Quick start, Feathers can work with any database, third party API or custom functionality by implementing your own services. When generating a custom service, a basic skeleton service will be created. You can remove the methods you don't need and add others you need.

While service methods still have to follow the standard or custom method signatures, the parameter and return types can be whatever works best for the service you are implementing. If a service method is only for internal use (and not for clients to call) there are no method signature or return value restrictions.

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

interface MyParams extends Params {}

class MyService {
  async find(params: MyParams) {
    return {
      message: 'This type is inferred'
    }
  }

  async get(id: Id) {
    return [
      {
        id
      }
    ]
  }

  async create(data: Message, params: MyParams) {
    return data
  }

  // Custom method made available to clients needs to have `data` and `params`
  async customMethod(data: CustomMethodData, params: MyParams) {}

  // A method that is only available internally can do anything
  async anyOtherMethod() {
    const [entry] = await this.get('david')

    return entry.id
  }
}
import type { Id, NullableId, Params } from '@feathersjs/feathers'

interface MyParams extends Params {}

class MyService {
  async find(params: MyParams) {
    return {
      message: 'This type is inferred'
    }
  }

  async get(id: Id) {
    return [
      {
        id
      }
    ]
  }

  async create(data: Message, params: MyParams) {
    return data
  }

  // Custom method made available to clients needs to have `data` and `params`
  async customMethod(data: CustomMethodData, params: MyParams) {}

  // A method that is only available internally can do anything
  async anyOtherMethod() {
    const [entry] = await this.get('david')

    return entry.id
  }
}
class MyService {
  async find(params) {
    return {
      message: 'This type is inferred'
    }
  }

  async get(id) {
    return [
      {
        id
      }
    ]
  }

  async create(data, params) {
    return data
  }

  // Custom method made available to clients needs to have `data` and `params`
  async customMethod(data, params) {}

  // A method that is only available internally can do anything
  async anyOtherMethod() {
    const [entry] = await this.get('david')

    return entry.id
  }
}
export {}
class MyService {
  async find(params) {
    return {
      message: 'This type is inferred'
    }
  }

  async get(id) {
    return [
      {
        id
      }
    ]
  }

  async create(data, params) {
    return data
  }

  // Custom method made available to clients needs to have `data` and `params`
  async customMethod(data, params) {}

  // A method that is only available internally can do anything
  async anyOtherMethod() {
    const [entry] = await this.get('david')

    return entry.id
  }
}
export {}

getOptions

The getOptions function is a function that returns the options based on the application that will be passed to the service class constructor. This is where you can pass common adapter options as well as MongoDB or SQL specific or custom service options.

Released under the MIT License.