Files
directus/docs/guides/extensions/creating-a-custom-api-hook.md
rijkvanzanten e703d1e928 Add docs
2020-09-22 16:09:02 -04:00

2.0 KiB

Creating a Custom API Hook

Custom hooks are dynamically loaded from your configured extensions folder.

Custom hooks are registered using a registration function:

// extensions/hooks/my-hook/index.js

module.exports = function registerHook() {
	return {
		'item.create.articles': function() {
			axios.post('http://example.com/webhook');
		}
	}
}

Register function return an object with key = event, value = handler function.

The registerHook function receives one parameter: context. context holds the following properties:

  • services — All API interal services
  • exceptions — API exception objects that can be used to throw "proper" errors
  • database — Knex instance that's connected to the current DB
  • env — Parsed environment variables

Each handler function gets a context parameter with the following properties:

  • event — Full event string
  • accountability — Information about the current user
  • collection — Collection that's being modified
  • item — Primary key(s) of the item(s) that's being modified
  • action — Action that's performed
  • payload — Payload of the request

Events that are prefixed with .before run before the event is completed, and are blocking. These allow you to check / modify the payload before it's processed.


Full example:

// extensions/hooks/sync-with-external/index.js

module.exports = function registerHook({ services, exceptions }) {
	const { ServiceUnavailableException, ForbiddenException } = exceptions;

	return {
		// Force everything to be admin only at all times
		'item.*.*': async function({ item, accountability }) {
			if (accountability.admin !== true) throw new ForbiddenException();
		},
		// Sync with external recipes service, cancel creation on failure
		'item.recipes.create.before': async function(input) {
			try {
				await axios.post('https://example.com/recipes', input);
			} catch (error) {
				throw new ServiceUnavailableException(error);
			}

			input[0].syncedWithExample = true;

			return input;
		}
	}
}