NestJS: Clean Code With Decorators

LiftOff LLC
2 min readMar 29, 2022

--

I mainly use decorators to keep my code clean, readable in a more logical and expressive way. To be honest I am heavily inspired by annotation usage of Java Spring Boot. In this article, I will be concentrating on one technique where I have used decorators to clean my code.

What is a Decorator?

TL;DR Decorator is a sort of declaration that can be used changing behaviour of a property or adding meta data to a class/property/method or extending functionality of a method etc.
In short, a function applied with prefix @ that gets automatically executed at runtime.

Example:
@Min() Can be used to add constraint on property age that validates the value being set.

@Min(18)
public age: number;

Premise

In one of our recent projects, I had to apply concurrency lock on an existing method. Distributed shared lock is pretty easy and achievable in many ways. I chose Redis andSETNX command for this purpose.

See more on this: Distributed Shared Lock With Redis

Note: Distributed shared lock with Redis is not the scope of this article.

Let’s assume we have a LockService that exposes two methods acquireLock(key) and releaseLock(key) See: Service class code

Now, three common steps whenever to apply concurrency lock on any existing method as follows

  1. Call the acquireLock() at the very beginning of the method.
  2. Wrap the entire existing method code in try/catch
  3. Call the releaseLock() in finally block

Disadvantage Of Above Code Style

The above code looks pretty messy and cumbersome every time any existing method needed to be wrapped with concurrency lock.

End Goal

The goal is to get rid of the above three common steps required every time we need locking.

Let’s look at the custom decorator @ConcurrencyLock() that will be used in place to wrap the existing function and will clean the above messy code.

Implementation Of @ConcurrencyLock() decorator

We can achieve the above goal easily with Method Decorator. Let’s have a look into the code.

Explanation

I am not going to explain line by line. I believe, little javascript/typescript learning would suffice to understand the code easily.

Line 12: const LockServiceinjector = Inject(LockService);

NestJS has Inject API that can be used to get LockService injector ( Not documented anywhere ). Got from stackoverflow :)

Line 19: LockServiceinjector(target, 'lockService');

This is same as injecting service via constructor.

Line 22: descriptor.value = async function wrapper(...args: any[])...

It’s the wrapper function that overrides the existing function and invokes the original method internally return await method.apply(this, args);

Conclusion

Don’t overlook decorators. They are cool building blocks to work with. Don’t confine yourself using the only decorators provided by the framework out of the box, better off, code your own decorators.

Good Luck :)

--

--

LiftOff LLC

We are business accelerator working with startups / entrepreneurs in building the product & launching the companies.