Steps to the Clean Code: Reusable validation in NodeJS + NestJS projects.
In this article, I just want to share how I do the validation of the dto’s for services and controllers in APIs based on NestJS and build-in validation library — class-validator.
Intro
I think everyone had a problem with validation on both levels — controllers and services. But it was always a question of how to avoid copy/pasting because data in the service dto and controller getting from request payload — really almost the same.
So my solution for this it’s to create dto’s with class-validator and use simple run time validation on the service level the same way controllers do with decorators.
Enough talking, there the code goes:
Examples
My main goal is to simplify the validation process and let us reuse the code in other places. I suggest creating a decorator, which will wrap the service method and if the incoming parameter is dto — then run validation:
Now we need some dto to define. Let’s say we gonna implement a method to update user details like email, name, and website URL:
Let’s define an interface for our future service:
And here it goes simple implementation:
So now we going to define the request schema, and reuse code from our dto.
Here we using @nestjs/mapped-types
library, which provides function OmitType — works identical to typescript Omit but for classes.
Bring it all together
So now finally we can create a controller. Here we basically using schema to validate the request body and take userId from the path. But service dto requires so all data from the request body and userId from the path to be in the same object.
As you can see in the code example, we really achieved two things:
- two-level validation — service and controller do validation for the incoming data
- no copy/pasting
- easy way to add validation into the service — all we need to do just to declare correct dto
Conclusion
This is a good way to reuse validation in both levels — services and controllers. Each time now something will call .updateUser() method, and it will run validation as well, so no need to implement it inside of the method. Plus ValidateArgs decorator is really simple to use, which altogether reduces the code base, and avoids copy/paste :)