Skip to content
KeystoneJS LogoKeystoneJSv5

Hooks API

Hooks give solution developers a way to add custom logic to the framework of lists, fields and operations Keystone provides.

This document describes:

  • How and where to configure hooks of different types
  • The specific arguments and usage information of different hook sets

For a more general overview of the concepts, patterns and function of the Keystone hook system, see the Hook Guide.


Hook Types

Hooks can be categories into three types depending on where in the list schema they're attached:

The hook sets that span these types have very similar signatures. Any differences are called out in the documentation below.

List Hooks

List hooks can be defined by the system developer by specifying the hooks attribute of a list configuration when calling createList(). Hooks for the create, update and delete operations are available.

Usage

keystone.createList('User', {
  fields: {
    name: { type: Text },
    ...
  },
  hooks: {
    // Hooks for create and update operations
    resolveInput: async (...) => { ... },
    validateInput: async (...) => { ... },
    beforeChange: async (...) => { ... },
    afterChange: async (...) => { ... },

    // Hooks for delete operations
    validateDelete: async (...) => { ... },
    beforeDelete: async (...) => { ... },
    afterDelete: async (...) => { ... },
  },
  ...
});

Field Hooks

Field hooks can be defined by the system developer by specifying the hooks attribute of a field configuration when calling createList(). Hooks for the create, update and delete operations are available.

Usage

keystone.createList('User', {
  fields: {
    name: {
      type: Text,
      hooks: {
        // Hooks for create and update operations
        resolveInput: async (...) => { ... },
        validateInput: async (...) => { ... },
        beforeChange: async (...) => { ... },
        afterChange: async (...) => { ... },

        // Hooks for delete operations
        validateDelete: async (...) => { ... },
        beforeDelete: async (...) => { ... },
        afterDelete: async (...) => { ... },
      },
      ...
    },
    ...
  },
  ...
});

Field Type Hooks

Field Type hooks are associated with a particular field type and are applied to all fields of that type. Custom field types can implement hooks by implementing the following hook methods on the Field base class. See the Custom Field Types guide for more info.

Hooks for the create, update and delete operations are available.

Usage

class CustomFieldType extends Field {
  // Hooks for create and update operations
  async resolveInput(...) { ... }
  async validateInput(...) { ... }
  async beforeChange(...) { ... }
  async afterChange(...) { ... }

  // Hooks for delete operations
  async beforeDelete(...) { ... }
  async validateDelete(...) { ... }
  async afterDelete(...) { ... }
}

Hook Sets

resolveInput

Used to modify the resolvedData.

  • Invoked after access control and field defaults are applied
  • Available for create and update operations

The return of resolveInput can be a Promise or an Object. It should resolve to the same structure as the resolvedData. The result is passed to the next function in the execution order.

Arguments

ArgumentTypeDescription
operationStringThe operation being performed (ie. create or update)
existingItemObject or undefinedThe current stored item (or undefined for create operations)
originalInputObjectThe data received by the GraphQL mutation
resolvedDataObjectThe data received by the GraphQL mutation plus defaults values
contextApollo ContextThe Apollo context object for this request
actionsObjectContains a query functions that queries the list within the current operations context, see Query Helper

Usage

const resolveInput = ({
  operation,
  existingItem,
  originalInput,
  resolvedData,
  context,
  actions,
}) => {
  // Input resolution logic
  // Object returned is used in place of resolvedData
  return resolvedData;
};

validateInput

Used to verify the resolvedData is valid.

  • Invoked after all resolveInput hooks have resolved
  • Available for create and update operations

If errors are found in resolvedData the function should either throw or call the supplied addFieldValidationError argument. Return values are ignored.

Arguments

ArgumentTypeDescription
operationStringThe operation being performed (ie. create or update)
existingItemObject or undefinedThe current stored item (or undefined for create operations)
originalInputObjectThe data received by the GraphQL mutation
resolvedDataObjectThe data received by the GraphQL mutation plus defaults values
contextApollo ContextThe Apollo context object for this request
actionsObjectContains a query functions that queries the list within the current operations context, see Query Helper
addFieldValidationErrorFunctionUsed to set a field validation error; accepts a String

Usage

const validateInput = ({
  operation,
  existingItem,
  originalInput,
  resolvedData,
  context,
  actions,
  addFieldValidationError,
}) => {
  // Throw error objects or register validation errors with addFieldValidationError(<String>)
  // Return values ignored
};

beforeChange

Used to cause side effects before the primary operation is executed.

  • Invoked after all validateInput hooks have resolved
  • Available for create and update operations

beforeChange hooks can't manipulate the data passed to the primary operation but perform operations before data is saved. Return values are ignored.

Arguments

ArgumentTypeDescription
operationStringThe operation being performed (ie. create or update)
existingItemObject or undefinedThe current stored item (or undefined for create operations)
originalInputObjectThe data received by the GraphQL mutation
resolvedDataObjectThe data received by the GraphQL mutation plus defaults values
contextApollo ContextThe Apollo context object for this request
actionsObjectContains a query functions that queries the list within the current operations context, see Query Helper

Usage

const beforeChange = ({
  operation,
  existingItem,
  originalInput,
  resolvedData,
  context,
  actions,
}) => {
  // Perform side effects
  // Return values ignored
};

afterChange

Used to cause side effects after the primary operation is executed.

  • Invoked after the primary operation has completed
  • Available for create and update operations

afterChange hooks perform actions after data is saved. It receives both the "pre-update" item that was stored (existingItem) and the resultant, "post-update" item data (updatedItem). This includes any DB-level defaults. Notably, for create operations, this includes the item's id.

Return values are ignored.

Arguments

ArgumentTypeDescription
operationStringThe operation being performed (ie. create or update)
existingItemObject or undefinedThe previously stored item (or undefined for create operations)
originalInputObjectThe data received by the GraphQL mutation
updatedItemObjectThe new/currently stored item
contextApollo ContextThe Apollo context object for this request
actionsObjectContains a query functions that queries the list within the current operations context, see Query Helper

Usage

const afterChange = ({
  operation,
  existingItem,
  originalInput,
  updatedItem,
  context,
  actions,
}) => {
  // Perform side effects
  // Return values ignored
};

validateDelete

Used to verify a delete operation is valid, ie. will maintain data consitency.

  • Invoked after access control has been tested
  • Available for delete operations

Should throw or register errors with addFieldValidationError(<String>) if the delete operation is invalid.

Arguments

ArgumentTypeDescription
operationStringThe operation being performed (delete in this case)
existingItemObjectThe current stored item
contextApollo ContextThe Apollo context object for this request
actionsObjectContains a query functions that queries the list within the current operations context, see Query Helper
addFieldValidationErrorFunctionUsed to set a field validation error; accepts a String

Usage

const validateDelete = ({
  operation,
  existingItem,
  context,
  actions,
  addFieldValidationError,
}) => {
  // Throw error objects or register validation errors with addFieldValidationError(<String>)
  // Return values ignored
};

beforeDelete

Used to cause side effects before the delete operation is executed.

  • Invoked after all validateDelete hooks have resolved
  • Available for delete operations

Perform actions before the delete operation is executed. Return values are ignored.

Arguments

ArgumentTypeDescription
operationStringThe operation being performed (delete in this case)
existingItemObjectThe current stored item
contextApollo ContextThe Apollo context object for this request
actionsObjectContains a query functions that queries the list within the current operations context, see Query Helper

Usage

const beforeDelete = ({
  operation,
  existingItem,
  context,
  actions,
}) => {
  // Perform side effects
  // Return values ignored
};

afterDelete

Used to cause side effects before the delete operation is executed.

  • Invoked after the delete operation has been executed
  • Available for delete operations

Perform actions after the delete operation has been executed. This is the last chance to operate on the previously stored item, supplied as existingItem.

Return values are ignored.

Arguments

ArgumentTypeDescription
operationStringThe operation being performed (delete in this case)
existingItemObjectThe previously stored item, now deleted
contextApollo ContextThe Apollo context object for this request
actionsObjectContains a query functions that queries the list within the current operations context, see Query Helper

Usage

const afterDelete = ({
  operation,
  existingItem,
  context,
  actions,
}) => {
  // Perform side effects
  // Return values ignored
};

actions Argument

All hooks receive an actions object as an argument. It contains helper functionality for accessing the GraphQL schema, optionally within the context of the current request. When used, this context reuse causes access control to be applied as though the caller themselves initiated an operation. It can therefore be useful for performing additional operations on behalf of the caller.

The actions object currently contains a single function: query.

Query Helper

Perform a GraphQL query, optionally within the context of the current request. It returns a Promise<Object> containing the standard GraphQL errors and data properties.

Argument

ArgumentTypeDescription
queryStringStringA graphQL query string
optionsObjectConfig for the query
options.skipAccessControlBooleanBy default access control of the user making the initial request is still tested. Pass as true to disable access control checks.
options.variablesObjectThe variables passed to the graphql query for the given queryString

Usage

const myHook = ({
  // ...
  actions: { query },
}) => {
  const queryString = `
    query {
      # GraphQL query here...
    }
  `;
  const options = {
    skipAccessControl: false,
    variables: { /* GraphQL variables here.. */ },
  };
  const { errors, data } = await query(queryString, options);

  // Check for errors
  // Do something with data
};

Have you found a mistake, something that is missing, or could be improved on this page? Please edit the Markdown file on GitHub and submit a PR with your changes.

Edit Page