Subscribers a.k.a Entity Listeners of TypeORM on NestJS

Semih Onay
4 min readJul 11, 2020

--

Photo by Tim Swaan on Unsplash

How and why we use them?

Imagine that you are building an archetypal e-commerce app backend. Generic product with properties etc. After a while, you comprehend that you need to inform users about changes in your inventory like stock changes, price changes, new arrivals.

What is Entity Listener?

It is a database specialized listener that listens to the CRUD events that happening in your database.

In TypeORM, It subscribes to your entity and listens to the changes.

After this point, I will use a Subscriber because of TypeORM wish to use it

What type of Subscribers TypeORM has?

I am not going into detail about each of them. It looks quite clear, right?

An Example

We will be developing a small application with only product service.

I will presume that you already installed and spinned up a NestJS app

or you may choose the shortcut for it :

https://github.com/Semyonic/shop-app

Photo by Marita Kavelashvili on Unsplash

Let’s say we have a very essential product with the following properties:

  • Name
  • Quantity
  • Price

Let us define our entity like the below snippet.

What about some magical decorators :

@CreateDateColumn, @UpdateDateColumn and @DeleteDateColumn

to handle dates for us ?

They act like subscribers. When the decorated action happens, they will update the date

A service to access the database via repositories. Be careful about how we handled the Update operation

Why did I used save for Update operation ?

TypeORM doesn’t like the update event.

We can’t access the changed data via update command over repositories with EventSubscriber.

I don’t prefer to use listeners in Entities so here is the subscriber:

You can implement beforeInsert function to hash the user passwords before saving into the database

We implemented the EntitySubscriber interface for the Product partially. We didn’t implement other listeners but you can see them with the help of IntelliSense or CodeCompletion tool you like.

listenTo function Indicates that this subscriber-only listens to Product entity related events. You may choose to listen to all entities but I’m not going to explain it here for the context.

afterUpdate function works when the product price changes afterUpdate function runs and logs the changed price values into the console via a built-in logger.

Can it be declared dynamically?

There’s no documented way to do it but with the power of the Dependency Injection, we can achieve to get it injected by NestJS:

Then we no longer need a subscriber property in TypeORM configuration.

Tip: Publish a message with Redis or RabbitMQ to notify price changes for sending notifications to users that track this product

What about unsubscription?

I didn’t find anything about this one yet but I’ve seen metadata properties in the repository to get active listeners that’s all I know.

Here is the controller:

Normally, I would use a class-validator with DTO’s but I wanted to keep it short in this controller.

Our product.module to glue the parts that we developed so far

Finally the app.module. Don’t forget to add entities and subscribers like in the below snippet

Do not use such configuration for TypeORM like above 👆 Prefer Config Service approach to make it configurable

If everything goes right and you start your app with yarn start: dev

yarn start:dev

Let’s add a product first :

Then update the product price

And we get the change!

Conclusion

Having such event listeners helps to catch changes on data easily and in a more clean way instead of polluting your entity class with such business logic.

If you have any questions feel free to ask!

Thanks for the reading and you can find me on Twitter and GitHub!

--

--