How to use DTOs in nestjs outside of controllers? (messages coming from a queue) - nestjs

We have a Nestjs app that listens to a queue and gets a message. Whenever we get a message, we use it to send an email. We have a DTO for that:
export class SendEmailDTO {
#Expose()
#IsDefined()
#IsString()
subject: string;
We are using a library aws-sdk where we receive a message anytime there's a message in a queue:
// import { validate } from 'class-validator';
#SqsMessageHandler(process.env.EMAIL_REQUEST_CONSUMER_QUEUE_NAME)
async handleMessage(message: AWS.SQS.Message) {
// here we want to run validations for message using our DTO.
const errors = await validate(message);
if (errors.length !== 0) {}
}
We managed to use the validate method and validate the message received. But we don't like this approach since we are running the validations ourselves.
We would like to have the validation tight to the DTO, to mimic what nestjs does. Something like this:
export class SendEmailDTO {
#Expose()
#IsDefined()
#IsString()
subject: string;
constructor(input: Input) {
const errors = validate(input);
Logger.debug(errors, '### in SendEmailDTO constructor! errors');
}
}
But unfortunately it does not work. We are not sure if this is the right direction.
how can we run the validations within the constructor?
validate returns a promise, we need to wait, but we don't know how to do it within the constructor
are we totally wrong with this direction, and we can not use the validate method within the constructor?. If not, how can we use the DTO outside the nestjs controller world?

Related

NestJS Is a good aproach using DTO classes in request object?

I'm learning NestJS and now I'm working in a simple authentication application, at this point I configured global pipes to validations and I'm using dto classes for example to validate #Body() fields. I don't know if I can use DTO to validate #Request fields sent from login endpoint.
import { Controller, Post, Request, UseGuards } from '#nestjs/common';
import { AuthService } from './auth.service';
import { AuthGuard } from '#nestjs/passport';
#Controller()
export class AuthController {
constructor(private authService: AuthService) {}
#UseGuards(AuthGuard('local'))
#Post('auth/login')
async login(#Request() req: reqDto /* I would like to use DTO for validations*/) {
return this.authService.login(req.user);
}
}
PS: I'm using DTO to validate SingUp body In UserController.
#Post('/signup')
createUser(#Body() createUserDto: CreateUserDto) {
return this.userService.createUser(createUserDto);
}
#Request() and #Headers() are two decorators that skip validation via pipes. You can make a custom request decorator that does get called via pipes, but annotating the request object would be a lot of work. What would be better is to create a decorator that gets just the data you need off the request, and then make a DTO for that object and validate that as necessary

NestJs: set last interceptor before controller from global

CONTEXT
I am looking for a way to force the programmer to validate the authorization of each parameter of a request route.
The objective is to avoid possible security errors due to forgetting to validate the authorization of a parameter.
Some of you could say that this belongs more to the development cycle than to the framework itself, that this should be solved by specifying who is authorized to access a resource in the task definition, and that the tests would verify that this authorization is carried out correctly, but could be forgotten. So some of you will think that this would be solved in the subsequent code review, but it could be forgotten. So some of you will think well that would be solved in the functional test, anyway it could be forgotten.
My goal is to make sure that the programmer cannot forget that he must be aware of the authorization of the resource, even if he has to actively ignore the authorization for resources that are public.
How ​​do I intend to carry it out?
I thought the best way would be to set an interceptor just before entering the controller that checks that all parameters have been changed to an object like {nParameter: {value: nValue, validate: true}}. And in this way force the programmer to establish another interceptor before this one that does that mapping by setting the parameter as validated or not depending on the case.
The problem is that I don't see a way to set that interceptor globally and have it run last since having to enter it on every resource would take us back to where we started.
I want to think that with some observable magic it could be achieved, I have done this:
#Injectable()
export class SecurityInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest<Request>()
request.params = Object.entries(request.params)
.reduce((params, [key, value]) => {
params[key] = { value, validate: false }
return parameters
}, {} as any)
return next.handle().pipe(
map((response) => {
if (Object.values(request.params).some(({ validate }) => !validate)) {
throw new Error()
}
return response
}),
)
}
}
But I would like to prevent the controller from running if not all parameters are checked.

Is there a way to get request context within a decorator in Nest JS

I am trying to build a decorator to "log" request info
export const Tracking = () => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const method = descriptor.value;
descriptor.value = async function(...args: any[]) {
console.log(/** Request info */)
console.log(/** Headers, Body, Method, URL...*/)
return method.call(this, ...args);
}
}
}
and try to use it on a controller method like this.
export class Controller {
#Get('/path')
#Tracking()
public async getData(#Headers('user') user: User) {
return this.service.getData(user.id);
}
}
If this is impossible, is there a way to apply interceptor to some method of controller?
Or is there a thread(like)-level context for request?
Thanks!!
Decorators don't have access to the request information because of what a decorator is. It's a higher order function that is called to set metadata for the class, class member, class method, or class method parameter. This metadata can be read at runtime, but it is called and set essentially as soon the file is imported. Due to this, there's no way to call a decorator on each request, even Nest's #Body() and #Req() are called at the time of import and read at the time of the request (actually earlier but that's besides the point).
What you're looking for here sounds more like an interceptor, like Micael Levi and hoangdv have already mentioned. The Nest docs show a basic logging example, and there are packages out there like #ogma/nestjs-module (disclaimer: I'm the author) that handle this request logging/tracking for you including the addition of correlation IDs.

How to make database request in Nest.js decorator?

I want to find a table row by request parameter. I know how to do it in service but I'm trying
to do it also in decorator.
My decorator:
import { BadRequestException, createParamDecorator, ExecutionContext } from '#nestjs/common';
export const GetEvent = createParamDecorator((data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
const { eventId } = request.params;
// Something like in service:
// const event = await this.eventModel.findByPk(eventId);
// return event;
});
I know that it's impossible to inject service in decorator but maybe some hacks to make database requests before calling service methods?
Theoretically, you could use a pacakge directly (like if you use TypeORM you could use the typeorm package), but there's a few things to note:
decorators really shouldn't be calling databases, it'll lead to crazy difficult stack traces
decorator methods can't be async, so you'd need callbacks, which decorators don't really work well with
querying the database really should be done in the controller or service. Just a best practice.

Access request object within validation pipe

I am trying to access to Request object from within a Validation Pipe in nestjs
In order to verify uniqueness of certain fields, I require the ID/UUID parameters supplied with PUT/PATCH request (not available in the data structure itself)
any idea?
Currently, it is not possible to access the request object at all in a pipe. If you need the request you can use a guard or an interceptor.
If you are working on verifying uniqueness, that sounds like a part of business logic more than just about anything else, so I would put it in a service and handle the query to the database there. Just my two cents.
Edit 11/17/2020
After learning way more about how the framework works as a whole, technically it is possible to get the entire request object in a pipe. There are two ways to go about it.
Make the pipe #Injectable({ scope: Scope.REQUEST }) so that it is request scoped. This will end up creating a new pipe on each request, but hey, if that's your cup of tea then great.
Make a custom parameter decorator as custom decorators get completely passed into pipes as they are. Do note, that this could impact how the ValidationPipe is functioning if that is bound globally, at the class, or method level.
We can create a Pipe and access request object. We can move further and update the Body as well, if needed.
Following is an example scenario, where createdBy field should be added to the Body dynamically. Let's say user details are available from request:
// user.pipe.ts
import { Request } from 'express'
import { REQUEST } from '#nestjs/core'
import { Injectable, Inject, Scope, PipeTransform } from '#nestjs/common'
#Injectable({ scope: Scope.REQUEST })
export class UserPipe implements PipeTransform<any> {
constructor(#Inject(REQUEST) protected readonly request: Request) {}
transform(value) {
let email = this.request["user"].email;
value['createdBy'] = email;
return value
}
}
We can now use this in controller like this:
// someentity.controller.ts
#Post()
public async create(
#Body(SetUserPipe) dto: SomeEntityDto,
): Promise<SomeEntity> {
....
}

Resources