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.

FlowEventParams
Login Flow   Set Account PassworduserId
Login Flow New User CreateduserId, email
Login FlowUnsuccessful User RegistrationuserId, reason, error
Login Flow Grant Permission SetuserId, roles, email, groups
Login Flow Mark Email VerifieduserId, email
Login Flow User Signed InuserId, email, ipaddress, mac address
Login FlowUnsuccessful Sign In AttemptuserId, email, ipaddress, mac address
Login FlowReset Password RequestuserId, email, ipaddress, mac address
Login FlowUnauthorized 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.

comments powered by Disqus