Supercharge provides you a handy event dispatcher implementing a publish/subscribe model for events occuring in your application. Events are a great way to decouple logic in your application, for example from route handlers.
For example, a user registers for your application and you want to send a welcome mail. The route handler shouldn’t wait for the mailer to send the mail. Instead, you can dispatch a UserRegistered
event to kick off a listener sending the mail.
You should put your event classes in the app/events
directory and listeners into app/listeners
. Supercharge will automatically pick up events and listeners when your server starts. Both directories may not exist in your application. You can go ahead and create them on your own or let the Craft CLI create them when scaffolding events and listeners.
Events in Supercharge are represented as classes. Each event class is a data container keeping the data for the listener. The event class also defines the identifier for listeners.
For example, imagine you’re publishing podcast episodes and want to dispatch an EpisodePublished
event on each release. The related event may look like this:
'use strict'
const Event = require('@supercharge/framework/event')
class EpisodePublished extends Event {
/**
* Create a new instance that keeps the event related data.
* The event instance containing the data is passed
* to the event listeners.
*
* @param {Object} podcast - the related podcast
*/
constructor (podcast) {
super()
this.podcast = podcast
}
/**
* Returns the event identifier. Every listener for this event
* must return the same value in their `on()` method.
*/
emit () {
return 'podcast.episode.published'
}
}
module.exports = EpisodePublished
The event class itself has no logic to handle dispatched events itself. The emit
method returns the event identifier each listener has to implement in their on()
method. The emit
function in events is optional. If you leave it, the event’s class name is used as the event identifier.
Event listeners implement the actual event handling logic. The listeners receive the event instance in their async handle(event)
method:
'use strict'
class NotifyListenersAboutNewEpisode {
/**
* Returns the event name or an array of event names to listen on.
*
* @returns {String|Array}
*/
on () {
return 'podcast.episode.published'
}
/**
* Handle the event.
*/
async handle (event) {
const podcast = event.podcast
// notify subscribers about the new episode
}
}
module.exports = NotifyListenersAboutNewEpisode
Remember that the on()
method identifies the related event. If the event has no emit()
method, the on()
method of your listener should return the event’s class name.
Typically, you’ll use “user” events in your application. For situations where you want to listen for process or system events, you should implement the type()
method.
For example, system events are unhandledRejection
, SIGTERM
, or any other low-level event you’ll receive through the Node.js process
. Here’s a sample event listener for the SIGTERM
event.
'use strict'
class SigtermListener {
on () {
return 'SIGTERM'
}
/**
* Handle the event.
*/
async handle (event) {
// gracefully shut down the system
}
/**
* The event dispatcher supports the `user` and `system` types.
* Use the `system` type for Node.js process listeners,
* the `user` type for your custom events.
*/
type () {
return 'system'
}
}
module.exports = SigtermListener
If you put all your events into the app/events
and event listeners into the app/listeners
directories, the framework will automatically register the listeners to their events. Your responsibility is to ensure that listeners implement the on()
method returning the event identifier they may listen on.
Typically, you’ll register events and listeners as seperate classes. The event bootstrapper will then pick up all events and listeners and connect the related classes.
Supercharge still allows you to register a callback-based event manually using the Event
class from the framework:
const Event = require('@supercharge/framework/event')
Event.on('my.event.name', data => {
// handle the event
})
Please notice that you can’t place these type of events in the app/events
directory because Supercharge requires all files in this directory to be an event class.
The Event
class in the Supercharge framework provides a static .fire()
method to dispatch events. You may pass an instance of the event to Event.fire()
and the framework dispatches this event to all its registered listeners:
const Event = require('@supercharge/framework/event')
const UserRegisteredEvent = require('../../events/auth/user-registered')
{
method: 'POST',
path: '/signup',
options: {
handler: async (request, h) => {
// user signup logic
Event.fire(new UserRegisteredEvent(user))
return h.redirect('/home')
}
}
}