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.

Hooks

Generating a hook

A new hook can be generated via

npx feathers generate hook
npx feathers generate hook

Hook name

The hook generator will first ask for a name. Based on the name it will create a kebab-cased filename in the hooks/ folder that exports a camelCased hook function. For example a name of my fancy Hook will create a src/my-fancy-hook.ts file that exports a myFancyHook hook function.

Hook types

There are two hook types that can be generated.

tip

For more information see the hooks API documentation.

Around hooks

Around hooks allow to control the entire before, after and error flow in a single function. An around hook is an async function that accepts two arguments:

  • The hook context
  • An asynchronous next function. Somewhere in the body of the hook function, there is a call to await next(), which calls the next hooks OR the original function if all other hooks have run.
ts
import type { HookContext, NextFunction } from '../declarations'

export const myFancyHook = async (context: HookContext, next: NextFunction) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
  await next()
  // Do things after here
}
import type { HookContext, NextFunction } from '../declarations'

export const myFancyHook = async (context: HookContext, next: NextFunction) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
  await next()
  // Do things after here
}
export const myFancyHook = async (context, next) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
  await next()
  // Do things after here
}
export const myFancyHook = async (context, next) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
  await next()
  // Do things after here
}

You can wrap the await next() in a try/catch block to also handle errors.

Before, after, error

Before, after or error hooks are async functions that take the hook context as the parameter.

ts
import type { HookContext } from '../declarations'

export const myFancyHook = async (context: HookContext) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
}
import type { HookContext } from '../declarations'

export const myFancyHook = async (context: HookContext) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
}
export const myFancyHook = async (context) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
}
export const myFancyHook = async (context) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
}

Context types

If the hook is for a specific service, you can pass the service as a generic to the HookContext type which will give you the correct types for context.data, context.result and context.params:

ts
import type { UserService } from '../services/users/users'
import type { HookContext } from '../declarations'

export const myFancyUserHook = async (context: HookContext<UserService>) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
}
import type { UserService } from '../services/users/users'
import type { HookContext } from '../declarations'

export const myFancyUserHook = async (context: HookContext<UserService>) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
}
export const myFancyUserHook = async (context) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
}
export const myFancyUserHook = async (context) => {
  console.log(`Running hook ${name} on ${context.path}.${context.method}`)
}

Registering hooks

A generated hook can be registered as an application hook or as a service hook. Also see the hook registration API documentation.

Profiling example

To log some basic profiling information like which method was called and how long it took to run you can create a new around hook called profiler via

npx feathers generate hook
npx feathers generate hook

Then update src/hooks/profiler.ts as follows:

ts
import type { HookContext, NextFunction } from '../declarations'
import { logger } from '../logger'

export const profiler = async (context: HookContext, next: NextFunction) => {
  const startTime = Date.now()

  await next()

  const runtime = Date.now() - startTime

  console.log(`Calling ${context.method} on service ${context.path} took ${runtime}ms`)
}
import type { HookContext, NextFunction } from '../declarations'
import { logger } from '../logger'

export const profiler = async (context: HookContext, next: NextFunction) => {
  const startTime = Date.now()

  await next()

  const runtime = Date.now() - startTime

  console.log(`Calling ${context.method} on service ${context.path} took ${runtime}ms`)
}
import { logger } from '../logger.js'

export const profiler = async (context, next) => {
  const startTime = Date.now()

  await next()

  const runtime = Date.now() - startTime

  console.log(`Calling ${context.method} on service ${context.path} took ${runtime}ms`)
}
import { logger } from '../logger.js'

export const profiler = async (context, next) => {
  const startTime = Date.now()

  await next()

  const runtime = Date.now() - startTime

  console.log(`Calling ${context.method} on service ${context.path} took ${runtime}ms`)
}

And add it in src/app.ts as an application hook after the logError hook as follows:

ts
import { profiler } from './hooks/profiler'

//...

// Register hooks that run on all service methods
app.hooks({
  around: {
    all: [logError, profiler]
  },
  before: {},
  after: {},
  error: {}
})
import { profiler } from './hooks/profiler'

//...

// Register hooks that run on all service methods
app.hooks({
  around: {
    all: [logError, profiler]
  },
  before: {},
  after: {},
  error: {}
})
import { profiler } from './hooks/profiler.js'

//...

// Register hooks that run on all service methods
app.hooks({
  around: {
    all: [logError, profiler]
  },
  before: {},
  after: {},
  error: {}
})
import { profiler } from './hooks/profiler.js'

//...

// Register hooks that run on all service methods
app.hooks({
  around: {
    all: [logError, profiler]
  },
  before: {},
  after: {},
  error: {}
})

Released under the MIT License.