CodeNewbie Community

Cover image for Adonis Js - Events and Mailing Part 2
Ted Ngeene
Ted Ngeene

Posted on • Originally published at tngeene.com

Adonis Js - Events and Mailing Part 2

Curiosity keeps leading us down new paths. ~ Walt Disney

It is often said that in programming there's always more than one way of doing things. The maxim is that to grow we must be open to new ideas...new ways of doing things...new ways of thinking are always applicable in our lives as developers.

In this second piece of implementing events and mailing in Adonis, I'll demonstrate another technique we can use to capture different events in our applications.

A reminder that the entire source code for this project can be found here.
Let's start.

Using the built-in Adonis event emitter module

For this guide, we'll use the built-in Event emitter module that comes in AdonisJs. You can peruse the official event documentation to have a better understanding of this concept.

We'll implement the same flow we did in our previous article, where the user receives a notification email upon registration to activate their account, so be sure to check it out!

What is the AdonisJs event module?

According to the adonis documentation, "The AdonisJS event emitter module is built on top of emittery".

Emittery is a modern async event emitter for node.js.

Some basic knowledge of the node.js event loop would help you better understand it but is not necessary.

Usage

node ace make:prldfile events
Enter fullscreen mode Exit fullscreen mode

This command creates a new events.ts file in the contracts directory. This file is the entry point for all events in our application. Select all options prompted by the CLI.

import User from 'App/Models/User'

declare module '@ioc:Adonis/Core/Event' {
  interface EventsList {
    'new:user': { newUser: User }
  }
}

Enter fullscreen mode Exit fullscreen mode

The Event.on method registers a new event listener. It accepts the name of the event, in our case new:user, followed by a method to handle the events as the arguments.

Listener Classes

Listener classes define the logic for our events. This is similar to the model function we defined in the last post.
Conventionally event listeners are stored inside the app/Listeners directory. However, you can customize the namespace inside the .adonisrc.json file.

To make a new event listener class that will handle the emailing, run the following command.

node ace make:listener User

Enter fullscreen mode Exit fullscreen mode

A new User.ts file will be created under the app/Listeners/ directory. Open the newly created file and paste this code.

import Mail from '@ioc:Adonis/Addons/Mail'
import Env from '@ioc:Adonis/Core/Env'
import { EventsList } from '@ioc:Adonis/Core/Event'
import Route from '@ioc:Adonis/Core/Route'

export default class User {
  public async onNewUser({ newUser }: EventsList['new:user']) {
    const appDomain = Env.get('APP_URL')
    const appName = Env.get('APP_NAME')
    const defaultFromEmail = Env.get('DEFAULT_FROM_EMAIL')
    const currentYear = new Date().getFullYear()
    const url = Route.builder()
      .params({ email: newUser.email })
      .prefixUrl(appDomain)
      .makeSigned('verifyEmail', { expiresIn: '24hours' })
    await Mail.send((message) => {
      message
        .from(defaultFromEmail)
        .to(newUser.email)
        .subject('Please verify your email')
        .htmlView('emails/auth/verify', { user: newUser, url, appName, appDomain, currentYear })
    })
  }
}

Enter fullscreen mode Exit fullscreen mode

As you can see, the code above is very similar to what we'd defined earlier as the sendVerificationEmail() function. For a more detailed explanation, head over to that article and check out the description.

However, just as a recap, we're defining the mail sending capability and building a URL that will encode our user token. The token expires in 24 hours and is tied down to a named URL, verifyEmail. Now, onto the new stuff.

public async onNewUser({ newUser }: EventsList['new:user'])

We're defining an async function named, onNewUser inside the default User class that takes the newUser as an argument. The newUser argument is tied to the event we just defined before. There, it'll always ensure that the parameters passed will match the ones defined in the event declaration.

If you wish to pass more than one argument, you can always define them in the events.ts file by separating them with semicolons.


 'new:user': { newUser: User; <arg2>: <modelName; <arg3>: <modelName;... }

Enter fullscreen mode Exit fullscreen mode

Then calling the same arguments on the function declaration

public async onNewUser({
newUser,
arg2,
arg3,
....
})

Enter fullscreen mode Exit fullscreen mode

Finally, we can emit our event on the authController.

Import the events module

import Event from '@ioc:Adonis/Core/Event'

Enter fullscreen mode Exit fullscreen mode

Then right below the validation in the register function


const data = await request.validate({ schema: validations })
const newUser = await User.create(data)

Event.emit('new:user', {
  newUser,
})

Enter fullscreen mode Exit fullscreen mode

We're calling the new:user event we defined in the events.ts file as this is the event name, the second parameter is the arguments to take.

Note that the argument names must be named similarly to the arguments we passed to the event declaration. By this I mean that you have to name the variable newUser just as it's declared in the event declaration. The same follows when having multiple arguments.

Now, we'll test the event.

Testing

Remember to turn on the development server by running, node ace serve --watch`

Registration

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqw6psdvb6m4jd7thi1f.png

Email

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/seg2tvj2j71lu9teh6jf.png

Account activated

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/acxn2isxsxr1o7i4srq3.png

Resources

  1. The complete source code can be accessed on my Github profile, here.
  2. Frontend code for the email template can be found in this GitHub gist
  3. official adonis events documentation
  4. Node.js event loop.

Conclusion

In this article, we've learned another way of working with events in AdonisJs. It's entirely up to you to decide which method best works for you. That being said, always employ the most optimal approach.
If you have any queries, comment and insight, don't hesitate to reach out on my Twitter, personal website or simply by leaving a comment below.

I'll be going over models, migrations, and relationships in my next article. Till then...cheers!

Discussion (0)