I'm using Nestjs (7.x) and Fastify (with #nestjs/platform-fastify).
I'm trying to install Helmet in my project (fastify-helmet), but I'm not able to figure how to integrate/configure it with Nestjs. What's the proper way to have it onboard?
Here is my Nestjs bootstrap:
import { NestFactory } from '#nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '#nestjs/platform-fastify';
import { MainModule } from './main.module';
import * as helmet from 'fastify-helmet';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(MainModule);
await app.listen(3000, 0.0.0.0);
}
bootstrap();
You've got two options when it comes to registering middleware for fastify. The first is to get the instance of the HttpAdapter and use the register method from there. This can be done like so:
import { NestFactory } from '#nestjs/core';
import {
FastifyAdapter,
NestFastifyApplication,
} from '#nestjs/platform-fastify';
import * as helmet from 'fastify-helmet';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
app
.getHttpAdapter()
.getInstance()
.register(helmet);
await app.listen(3000);
}
bootstrap();
The other option is to pass the type to the NestFactory.create method and then use app.register. This can bee seen here
import { NestFactory } from '#nestjs/core';
import {
FastifyAdapter,
NestFastifyApplication,
} from '#nestjs/platform-fastify';
import * as helmet from 'fastify-helmet';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
app.register(helmet);
await app.listen(3000);
}
bootstrap();
Both ways are valid, though only the second option is type safe.
import { NestFactory } from '#nestjs/core';
import {
FastifyAdapter,
NestFastifyApplication,
} from '#nestjs/platform-fastify';
import { fastifyHelmet } from 'fastify-helmet';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
app.register(fastifyHelmet)
await app.listen(3000);
}
bootstrap();
try this instead. import fastifyHelmet from the package, use that to register.
Related
I'm trying to get PrismaService on my main.ts, but it's keep crashing. I'm new on this, can anyone help me to solve it?
My prisma.service.ts:
import { INestApplication, Injectable, OnModuleInit } from '#nestjs/common';
import { PrismaClient } from '#prisma/client';
#Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() {
await this.$connect();
}
async enableShutdownHooks(app: INestApplication) {
this.$on('beforeExit', async () => {
await app.close();
});
}
}
My main.ts:
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
import { PrismaService } from './prisma.service';
import { ValidationPipe } from '#nestjs/common';
import helmet from 'helmet';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({
allowedHeaders: '*',
origin: '*',
});
app.use(helmet());
app.use(helmet.hidePoweredBy());
app.use(helmet.contentSecurityPolicy());
const prismaService = app.get(PrismaService);
await prismaService.enableShutdownHooks(app);
app.useGlobalPipes(
new ValidationPipe({
transform: true,
whitelist: true,
forbidNonWhitelisted: true,
}),
);
await app.listen(process.env.PORT, () => console.log('runing...'));
}
bootstrap();
The error message:
Error: Nest could not find PrismaService element (this provider does not exist in the current context)
at InstanceLinksHost.get (/home/rafittu/wophi/alma/back/node_modules/#nestjs/core/injector/instance-links-host.js:15:19)
at NestApplication.find (/home/rafittu/wophi/alma/back/node_modules/#nestjs/core/injector/abstract-instance-resolver.js:8:60)
at NestApplication.get (/home/rafittu/wophi/alma/back/node_modules/#nestjs/core/nest-application-context.js:64:20)
at /home/rafittu/wophi/alma/back/node_modules/#nestjs/core/nest-factory.js:133:40
at Function.run (/home/rafittu/wophi/alma/back/node_modules/#nestjs/core/errors/exceptions-zone.js:10:13)
at Proxy.<anonymous> (/home/rafittu/wophi/alma/back/node_modules/#nestjs/core/nest-factory.js:132:46)
at Proxy.<anonymous> (/home/rafittu/wophi/alma/back/node_modules/#nestjs/core/nest-factory.js:181:54)
at bootstrap (/home/rafittu/wophi/alma/back/src/main.ts:18:29)
When I delete PrismaService from main.ts, server start normaly
Use app.get(PrismaService, { strict: false }). The strict: false is to say that AppModule doesn't directly provider the provider and to traverse the DI container to find it
After setting up the PrismaService in prisma.service.ts and enabling shutdown hooks in the main.ts file, you also need to do the following:
In the app.module.ts you need to add PrismaService as one of the providers:
...
import { PrismaService } from './prisma/prisma.service';
#Module({
imports: [],
controllers: [AppController],
providers: [AppService, PrismaService], // add PrismaService here
})
export class AppModule {}
I'm trying to unit test a middleware to avoid sending a request but I'm actually not able to retreive the middleware with .get
import { NestApplicationContext } from '#nestjs/core';
import { BodyParserMiddleware } from '../../../src/config/body-parser/body-parser.middleware';
import { FeaturesModule } from '../../../src/features/features.module';
describe('CatsController', () => {
let app: NestApplicationContext;
beforeAll(() => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
});
describe('findAll', () => {
it('should return an array of cats', async () => {
console.log(app.get(BodyParserMiddleware));
});
});
});
my app module looks like this
import { Module } from '#nestjs/common';
import { FeaturesModule } from './features/features.module';
#Module({
imports: [FeaturesModule],
})
export class AppModule {}
and the last one feature module
import { MiddlewareConsumer, Module, NestModule } from '#nestjs/common';
import { BodyParserMiddleware } from '../config/body-parser/body-parser.middleware';
#Module({
imports: [
AuthModule,
],
})
export class FeaturesModule implements NestModule {
configure(consumer: MiddlewareConsumer): void {
consumer.apply(BodyParserMiddleware).forRoutes('api/v*/*/get-many');
}
}
Nest could not find BodyParserMiddleware element (this provider does not exist in the current context)
this is the error that im having
anyone knows how to retreive the middleware from the app container?
Also when I try to get the Features module to see if there is any clue there where I can go I receive
FeaturesModule {}
I am trying to combine peer server with my nestjs application. Unfortunately it doesn't work as expected. I am creating a service containing the peer server instance and initialize it on application start. I also use this service to handle requests coming
in a specific controller. I did the configuration as follow:
main.ts
import { NestFactory } from '#nestjs/core';
import { NestExpressApplication } from '#nestjs/platform-express';
import { I18nMiddleware } from 'nestjs-i18n';
import { Logger, LoggerErrorInterceptor } from 'nestjs-pino';
import { AppModule } from './app.module';
import { PeerServerService } from './peer-server/peer-server.service';
import { PrismaService } from './prisma/prisma.service';
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
bufferLogs: true,
});
app.useLogger(app.get(Logger));
app.useGlobalInterceptors(new LoggerErrorInterceptor());
app.use(I18nMiddleware);
const prismaService = app.get(PrismaService);
const peerServerService = app.get(PeerServerService);
prismaService.enableShutdownHooks(app);
peerServerService.enablePeerServer(app);
await app.listen(3000);
}
bootstrap();
peer-server.service.ts
import { Injectable } from '#nestjs/common';
import { NestExpressApplication } from '#nestjs/platform-express';
import { ExpressPeerServer, PeerServerEvents } from 'peer';
import { Express } from 'express';
#Injectable()
export class PeerServerService {
peerServer: Express & PeerServerEvents;
enablePeerServer(app: NestExpressApplication) {
this.peerServer = ExpressPeerServer(app.getHttpServer(), {
path: '/myapp',
});
console.log('peer server: ', this.peerServer);
this.peerServer.get('/test', (req, res) => {
res.send('hello');
});
}
}
peer-server.controller.ts
import { All, Controller, Next, Req, Res } from '#nestjs/common';
import { NextFunction, Request, Response } from 'express';
import { PeerServerService } from './peer-server.service';
#Controller('/peer-server')
export class PeerServerController {
constructor(private readonly peerServerService: PeerServerService) {}
#All('*')
server(
#Req() request: Request,
#Res() response: Response,
#Next() next: NextFunction,
) {
const entryPointPath = '/peer-server/';
request.url = request.url.replace(entryPointPath, '/');
console.log('in route peer: ', request.url);
this.peerServerService.peerServer(request, response, next);
}
}
I verified that the server is correctly forwarded to the peer service with this request
this.peerServer.get('/test', (req, res) => {
res.send('hello');
});
Sending a request to /peer-server/test works but /peer-server/myapp returns 404
Has anyone ever done that successfully ?
I'm trying to create shared-module for microservices.
There are two packages:
#name/hub - ordinary HTTP-service
#name/lib - shared library
Library contains simple exception-filter module:
http.exception-filter.ts
import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '#nestjs/common';
import { Request, Response } from 'express';
#Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
message: exception.message,
});
}
}
exceptions-fitlers.module.ts
import { Module, Scope } from '#nestjs/common';
import { HttpExceptionFilter } from './http.exception-filter';
import { APP_FILTER } from '#nestjs/core';
#Module({
providers: [
{
provide: APP_FILTER,
scope: Scope.REQUEST,
useClass: HttpExceptionFilter,
},
],
})
export class ExceptionsFiltersModule {}
Service contains controller that uses this filter:
app.module.ts
import { Module } from '#nestjs/common';
import { ExceptionsFiltersModule } from '#name/nodejs-lib/dist';
#Module({
imports: [ExceptionsFiltersModule, ...],
})
export class AppModule {}
controller.ts
#Controller('app')
#UseFilters(new HttpExceptionFilter())
export class AppController{
#Post('/check')
#HttpCode(200)
async check(#Body() dto: A): Promise<B> {
throw new BadRequestException('Invalid data');
}
}
main.ts
import { NestFactory } from '#nestjs/core';
import { AppModule } from './modules/app.module';
import { ConfigService } from '#nestjs/config';
import { DocumentationBuilder, HttpExceptionFilter } from '#name/nodejs-lib/dist';
async function bootstrap() {
const app = await NestFactory.create(AppModule, { cors: true });
const config = app.get(ConfigService);
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(config.get<number>('HTTP_PORT'), () => {
logger.log(`HTTP Server: http://${config.get('HTTP_HOST')}:${config.get('HTTP_PORT')}`);
});
}
bootstrap().then();
Then I trying trigger this filter, I receive generic response:
{
"statusCode": 400,
"message": "Invalid data",
"error": "Bad Request"
}
If someone has opinion, please let me know. Thanks
I want to implement a global authentication guard in My NestJS application that will simply read certain headers and assign user values based on those headers, for every request that comes in.
I implemented this simple logic and registered my global guard in my main module, however for some reason all my requests fail with '401 Unauthorized'. I tried to place log messages inside internal.strategy.ts, however I don't see them getting called.
Any idea why the strategy is not called?
This is my main.ts:
import { NestFactory, Reflector } from '#nestjs/core';
import * as logging from './logging';
import { AppModule } from './app.module';
import config from './config';
import { LocalAuthGuard } from './auth/guards/local-auth.guard';
async function bootstrap(port: string | number) {
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new LocalAuthGuard())
await app.listen(port, '0.0.0.0');
logging.logger.info(`Listening on 0.0.0.0:${port}`);
}
bootstrap(config.port);
This is my auth.module.ts:
import { Module } from '#nestjs/common';
import { PassportModule } from '#nestjs/passport';
import { AuthService } from './auth.service';
import { InternalStrategy } from './stategies/internal.strategy';
#Module({
imports: [PassportModule],
providers: [AuthService, InternalStrategy ]
})
export class AuthModule {}
This is my auth.service.ts:
import { Injectable } from '#nestjs/common';
import { Role } from 'src/workspaces/interfaces/models';
#Injectable()
export class AuthService {
validateUser(headers: Headers): any {
const workspaceId = headers['workspace-id'];
const workspaceRole = Role[headers['workspace-role']];
return {
workspaceId: workspaceId,
workspaceRole: workspaceRole
}
}
}
This is my internal.strategy.ts:
import { Strategy } from 'passport-local';
import { PassportStrategy } from '#nestjs/passport';
import { Injectable, UnauthorizedException } from '#nestjs/common';
import { AuthService } from '../auth.service';
#Injectable()
export class InternalStrategy extends PassportStrategy(Strategy, 'internal') {
constructor(private authService: AuthService) {
super({ passReqToCallback: true });
}
async validate(req: Request): Promise<any> {
console.log('Validate internal strategy')
const user = await this.authService.validateUser(req.headers);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
Here is my local-auth.guard.ts:
import { Injectable } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
#Injectable()
export class LocalAuthGuard extends AuthGuard('internal') {}