Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

699
Views
Creating a Singleton EventEmittor in Nodejs & Express Project

I'm trying to create a Publisher-Subscriber pattern with Nodejs eventEmitters for my nodejs/express API project. My use-case is fairly simple:

  1. I want to emit events from various places in my project. For example, emit an event when a new user is created.
  2. Then I want a single place, where I listen to all the events and decide what actions to take.

This will require a singleton instance of eventEmitter because 'emit' and 'on' calls should happen on the same instance of 'event' object.

To achieve it, this is how my index.js looks:

const express = require('express')
const app = express()

const bodyParser = require('body-parser')
const routes = require('./api/routes')
const EventEmitter = require("events");
const eventEmitter = new EventEmitter();

const eventListeners = require('../src/subscribers/events');
//const eventSubs = new eventListeners();

app.use(eventListeners.eventSubscribers());

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.set('eventEmitter', eventEmitter);

app.get('/', (req, res) => res.send('App is working'))

app.use('/api', routes)

app.listen(3000, () => console.log('Example app listening on port 3000!'))

module.exports = {
  app
}

This is how my middleware/controller function looks(where I'm emitting event):

const createUser = async (req, res, next) => {
  var user = req.body
  try {
    console.log('in controller');

    await newUser(user)

    console.log(req.app.get('eventEmitter'));

    req.app.get('eventEmitter').emit('USER_CREATED', {email: user.email, name: user.name})

    res.status(200).send({success: true});
    next()

  } catch(e) {
    console.log(e.message)
    res.sendStatus(500) && next(e)
  }
}

And, this is how my event subscriber file looks:

const eventSubscribers = (req) => {
    const eventEmitter = req.app.get('eventEmitter');

    eventEmitter.on('USER_CREATED', ({ email, name }) => {
        console.log('event fired and captured')
    })
}

Using this, the event is getting emitted, but the event subscriber is not getting trigerred. I think there is something wrong with the way I'm accessing req/app objects in my subscriber. Also, I'm getting

TypeError: eventListeners.eventSubscribers is not a function

error in my index.js file. Questions I have:

  1. Is this the right way to create a publisher/subscriber pattern?
  2. How do I access req/app object instances in my event subscriber?
  3. What's the best way to make sure event subscriber file is loaded when the app loads?
over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Assuming everything else is correctly setup by you,
I think the cause of the error that you mentioned

TypeError: eventListeners.eventSubscribers is not a function

is that no function is passed to the middleware i.e as a middleware, shouldn't you just pass the eventListeners.eventSubscribers like this

app.use(eventListeners.eventSubscribers);

instead of like this

app.use(eventListeners.eventSubscribers());

If we compare both expressions above, express is not able to pass the request object in the second case as you are calling it but this function call is returning nothing to the express i.e kind of void, but in first case since you passed the function object reference to express, it then calls it as middleware(as a callback later and passes the request object in it while calling it).

Alternatively I think you don't need to use middleware for using the EventEmitter, you can just keep a single global custom instance consisting of EventEmitter as it's property and all the different event you want to listen, and then just use them wherever you require them.You can use the EventEmitter as a property of this custom to emit event in whatever module you want to by importing this custom module there.

This is the working example below

index.js file/entry file

const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const routes = require("./userRoute");
//const eventSubs = new eventListeners();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.get('/', (req, res) => res.send('App is working'))

app.use('/api', routes);

app.listen(3000, () => console.log('Example app listening on port 3000!'))

This is our global singleton custom instance using EventEmitter as a property.

const { EventEmitter } = require("events");

class CustomEventEmitter {

    eventEmitter;

    constructor() {
        this.eventEmitter = new EventEmitter();
        this.initialize();
    }

    getEventEmitter() {
        return this.eventEmitter;
    }

    initialize() {
        this.eventEmitter.on('USER_CREATED', ({ email, name }) => {
            console.log('event fired and captured with data', email, name);
        });
    }
}

module.exports = new CustomEventEmitter();

and here we use our global CustomEventEmitter module in our request routes i.e userRoute.js

const router = require("express").Router();
const customEventEmitter = require("./CustomEventEmitter");

const createUser = async (req, res, next) => {
    var user = req.body
    try {
        console.log('in controller');

        // await newUser(user)

        customEventEmitter.getEventEmitter().emit('USER_CREATED', { email: user.email, name: user.name })

        res.status(200).send({ success: true });
        next()

    } catch (e) {
        console.log(e.message)
        res.sendStatus(500) && next(e)
    }
}

router.post("/createUser", createUser)

module.exports = router;
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!