add decorators, filters, interceptors, guards, pipes

This commit is contained in:
Sergey Krylov 2025-06-10 06:00:56 +03:00
parent 909b375c93
commit b6f4107c8a
8 changed files with 133 additions and 1 deletions

26
src/app.controller.ts Normal file
View File

@ -0,0 +1,26 @@
import {
Body,
Controller,
Get,
Post,
UseGuards,
UsePipes,
} from '@nestjs/common';
import { UserAgentDecorator } from './common/decorators/user-agent.decorator';
import { AuthGuard } from './common/guards/auth.guard';
import { StringToLowercasePipe } from './common/pipes/string-to-lowercase.pipe';
@Controller()
export class AppController {
@UsePipes(StringToLowercasePipe)
@Post()
create(@Body('title') title: string) {
return `Movie ${title}`;
}
@UseGuards(AuthGuard)
@Get()
getProfile(@UserAgentDecorator() userAgent: string) {
return { name: 'FirstName', age: 22, userAgent };
}
}

View File

@ -1,5 +1,6 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { TaskModule } from './task/task.module';
import { MovieModule } from './movie/movie.module';
import { ReviewModule } from './review/review.module';
@ -17,7 +18,7 @@ import { PrismaModule } from './prisma/prisma.module';
ReviewModule,
ActorModule,
],
controllers: [],
controllers: [AppController],
providers: [],
})
export class AppModule {}

View File

@ -0,0 +1,9 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { Request } from 'express';
export const UserAgentDecorator = createParamDecorator(
(_data: unknown, context: ExecutionContext) => {
const request: Request = context.switchToHttp().getRequest();
return request.headers['user-agent'];
},
);

View File

@ -0,0 +1,34 @@
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
Logger,
} from '@nestjs/common';
import { Request, Response } from 'express';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
private readonly logger = new Logger(AllExceptionsFilter.name);
catch(exception: any, host: ArgumentsHost): any {
const context = host.switchToHttp();
const response: Response = context.getResponse();
const request: Request = context.getRequest();
const status =
exception instanceof HttpException ? exception.getStatus() : 500;
const message =
exception instanceof HttpException
? exception.message
: 'Internal server error';
this.logger.error(message, exception);
response.status(status).json({
status,
message,
timestamp: new Date().toISOString(),
path: request.baseUrl,
});
}
}

View File

@ -0,0 +1,24 @@
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { Request } from 'express';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const request: Request = context.switchToHttp().getRequest();
const token = request.headers.authorization;
if (!token || !token.startsWith('Bearer')) {
throw new UnauthorizedException('You are not authorized');
}
return true;
}
}

View File

@ -0,0 +1,22 @@
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common';
import { map, Observable } from 'rxjs';
@Injectable()
export class ResponseInterceptor implements NestInterceptor {
intercept(
context: ExecutionContext,
next: CallHandler<any>,
): Observable<any> {
return next.handle().pipe(
map((data) => ({
status: 'OK',
data,
})),
);
}
}

View File

@ -0,0 +1,12 @@
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
@Injectable()
export class StringToLowercasePipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata): any {
if (typeof value === 'string') {
return value.toLocaleLowerCase();
}
return value;
}
}

View File

@ -1,12 +1,16 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { AllExceptionsFilter } from './common/filters/all-exceptions.filter';
import { ResponseInterceptor } from './common/interceptors/response.interceptor';
import { loggerMiddlewareFunc } from './common/middlewares/logger/logger.middleware';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
app.use(loggerMiddlewareFunc);
app.useGlobalInterceptors(new ResponseInterceptor());
app.useGlobalFilters(new AllExceptionsFilter());
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();