An Intro to Architecture: Events & Hooks
This is the second installment of our introduction to Reaction's architecture. This series is largely driven by the flow chart available here.
In my previous post, I gave an overview of how to read the diagram and what this series is attempting to accomplish. Today, I'm digging into Reaction's event system and and discussing some of the things it enables you to do, both server side and client side. If you missed Part 1, you can catch up here.
Event System Flow
As seen in this diagram, we have 9 events that are available during the login flow process. Here's a list of those events, the "flow" that they are generated from (which is not used in the code), and the Params that you might have access to when hooking into these events.
Flow | Event | Params |
---|---|---|
Login Flow | Set Account Password | userId |
Login Flow | New User Created | userId, email |
Login Flow | Unsuccessful User Registration | userId, reason, error |
Login Flow | Grant Permission Set | userId, roles, email, groups |
Login Flow | Mark Email Verified | userId, email |
Login Flow | User Signed In | userId, email, ipaddress, mac address |
Login Flow | Unsuccessful Sign In Attempt | userId, email, ipaddress, mac address |
Login Flow | Reset Password Request | userId, email, ipaddress, mac address |
Login Flow | Unauthorized Reset Password Attempt Reported | userId, email |
Please note that most of these login flow events are forward-looking. They don't all exist yet in the code, but we're working towards it. The Params seen here are examples, and may not be the exact same params you have access to once these events are built.
I'm sure you can imagine how this will enable you to build quite a number of powerful plugins that don't require any change of core code.
Examples of Server-Side Hooks
Here, I'd like to share with you just a few examples of server-side event hooks. We've got quite a few hooks already built in and in use, so the server-side example will be a little more practical. In theory, you'll be able to hook into any server or client side hook in the same way.
onCreateUser hook
Here is an example of an event hook that runs on user creation.
const userDoc = Hooks.Events.run("onCreateUser", user, options);
run()
specifies that any callbacks added to this hook will be run successively.- The first argument,
"onCreateUser"
, becomes the name of this hook - The second argument,
user
, is the object or modifier on which to run the callbacks. This item is mutable and should be returned from any callback that is created. - The third argument,
options
, is an optional constant that will be passed along to each callback.
To hook into this event, we could do so by using the Hooks.Events.add()
method.
import { Hooks } from "/server/api"; // import Hooks
Hooks.Events.add("onCreateUser", (user, options) => {
//Do Stuff with user and/or options
const vip = checkIfUserIsVIP(user._id);
if (vip) {
// Add VIP to roles
}
return user; // Always return the first arg so other hooks run
})
Adding Roles in a Plugin
For our PayPal Express plugin, we have a couple routes that the user can get redirected to after payment. By default, Reaction disallows access to routes, so if we want to permit guest users to access these payment redirection routes, we need to add them to the set of default roles.
I didn't want to add the PayPal Express roles to the core code, since they are undefined routes (unless the PayPal Express plugin is active), so I hooked into the afterCoreInit
event, which runs after the server is started.
import { Reaction, Hooks } from "/server/api";
Hooks.Events.add("afterCoreInit", () => {
Reaction.addRolesToDefaultRoleSet({
allShops: true,
roleSets: ["defaultRoles", "defaultVisitorRole"],
roles: ["reaction-paypal/paypalDone", "reaction-paypal/paypalCancel"]
});
});
This code is in the server/startup/startup.js file in the payments-paypal
plugin.
This code runs when the core init()
process has finished in core.js
If you want to dig deeper into exactly how our hooks work, scope the code here.
What About Client Side?
We're still in the process of building out our client side event hooks. These will be primarily used for hooking into analytics, as everything else can be accomplished via server-side hooks.
We'll revisit this topic once our client side event library is more full-featured.
I hope this post has shown you how easy it is to hook into core Reaction functionality, all without having to change core Reaction code! As always, if you have any questions, leave them in the comments here or jump in our Gitter chatroom.