Meteor callback-hook
Tags: meteor
Published: 2020-06-27 11:10:18

This time around I'm taking a look on another internal Meteor package [callback-hook](https://atmospherejs.com/meteor/callback-hook).
As the name suggests this package provides a standard way to add hooks into Meteor code. This is super useful for those who want to extend Meteor core with hooks this is a package they need to know. It is also useful for package creators to implement.

Getting started is easy:
```js
import { Hook } from 'meteor/callback-hook'

const _myAwesomeHook = new Hook(options)
```

Now then, what are the options?
* `bindEnvironment` - should the current Meteor environment be passed to the hook?
* `exceptionHandler` - a function to handle exception or else it will propagate
* `debugPrintExceptions` - a string to identify the hook in terminal

Pretty straight forward. Now to allow users to add to the hook we need to make it accessible:
```js
export const myAwesomeHook = (func) => _myAwesomeHook.register(func)
```
That looks a pretty strange doesn't it? What is happening here is that this allows the user to create multiple functions that will be part of the hook. So you can have multiple handling of the hook at multiple places in the app. 

This then explains how you handle executing the hook:
```js
_myAwesomeHook.each(callback => {
  callback({ ...paramsForHook })
  return true
})
```
The iteration stops if you return a falsy value or throw an exception.

And that is it! For an actual example see the [Accounts.onLogin hook](https://docs.meteor.com/api/accounts-multi.html#AccountsCommon-onLogin).

Here is the full description from the hook class:
```js
// Encapsulates the pattern of registering callbacks on a hook.
//
// The `each` method of the hook calls its iterator function argument
// with each registered callback.  This allows the hook to
// conditionally decide not to call the callback (if, for example, the
// observed object has been closed or terminated).
//
// By default, callbacks are bound with `Meteor.bindEnvironment`, so they will be
// called with the Meteor environment of the calling code that
// registered the callback. Override by passing { bindEnvironment: false }
// to the constructor.
//
// Registering a callback returns an object with a single `stop`
// method which unregisters the callback.
//
// The code is careful to allow a callback to be safely unregistered
// while the callbacks are being iterated over.
//
// If the hook is configured with the `exceptionHandler` option, the
// handler will be called if a called callback throws an exception.
// By default (if the exception handler doesn't itself throw an
// exception, or if the iterator function doesn't return a falsy value
// to terminate the calling of callbacks), the remaining callbacks
// will still be called.
//
// Alternatively, the `debugPrintExceptions` option can be specified
// as string describing the callback.  On an exception the string and
// the exception will be printed to the console log with
// `Meteor._debug`, and the exception otherwise ignored.
//
// If an exception handler isn't specified, exceptions thrown in the
// callback will propagate up to the iterator function, and will
// terminate calling the remaining callbacks if not caught.
```

--------
If you like my work, please consider supporting me on [GitHub Sponsors ❤️](https://github.com/sponsors/StorytellerCZ).