How to set config for Fastify route config when using NestJS - nestjs

There is an option to set route config in Fastify like:
https://www.fastify.io/docs/latest/Routes/#config
fastify.get('/en', { config: { output: 'hello world!' } }, handler)
but is there an option to set config when using NestJS with Fastify?
// where to put config for route
#Post('/en')
async createResource(
#Body() payload: any,
): Promise<void> {}

Related

NestJs include TypeORM repository in middleware

I have the following middleware to log all http requests:
#Injectable()
export class RequestMiddleware implements NestMiddleware {
constructor(
#InjectRepository(Request) private requestsRepository: Repository<Request>,
) {}
private readonly logger = new Logger('HTTP');
use(request: Request, response: Response, next: NextFunction) {
response.on('finish', () => {
const { method, originalUrl } = request;
const { statusCode, statusMessage } = response;
const message = `${method} ${originalUrl} ${statusCode} ${statusMessage}`;
return this.logger.log(message);
});
next();
}
}
My goal is to log all requests to a database. I am using TypeORM so I would like to inject the Request repository and log each request that way. When I do this I receive the following error:
Error: Nest can't resolve dependencies of the class RequestMiddleware
The issue is that this middleware isn't part of a module, it's just a single typescript file so how do I import the TypeORM repo module into a normal typescript file so I can use it?
In the module where RequestMiddleware is defined and used, TypeormModule.forFeature([Request]) needs to be added to the imports array

Nestjs - how to get session in middleware

im trying to add graphql to nestjs app. I use postgraphile for the graphql server.
everything works, but i don't know how to protect the '/graphql' endpoint.
the login is done via session, through the nestjs app.
on the needed endpoints (in the existed nestjs app) there is a Session guard which works fine.
i want to add the same behavior to the graphql endpoint.
this is the graphql code:
export const graphqlBootstrap = async (app: INestApplication) => {
app.use(cors());
// what i want to achieve
app.use('/graphql', (req, res, next) => {
if (!req.session.user) res.send('Authetication Error`);
next();
})
app.use(
postgraphile(...)
and the nestjs code the init it:
const bootstrap = async () => {
const { app, start } = await createApplication(TearupsApplicationModule);
app.useGlobalInterceptors(new ApiResponseInterceptor());
configureHiddenFileUploadEndpoint(app.getHttpAdapter());
await Promise.all(app.get(INITIATION_SEQUENCE).map((fn) => fn()));
await graphqlBootstrap(app); // <--
await start();
app.get(EventsEmitter).init(app);
};
is it possible to use the session in a middleware?
I don't know how to reach the ExecutionContext that exist in the Guard.
I read in the docs that there is also ArgumentsHost which might hold the session, but i also don't know how to get it in simple middleware(app.use(...))
Edit 1
i tried to add a middleware to the app module, with forRoutes call.
but the middleware isn't called with the graphql route /graphql.
also, when using route: / - there is no session on the request.
middleware:
export function Logger(req: any, res: Response, next: NextFunction) {
if (req.session) console.log(`Request...`, req.session.user);
next();
}
App Module:
export class MyApp implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(Logger).forRoutes('/');
}
Edit 2
tried this now, still didn't work:
export class MyApp implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(logger)
.forRoutes({ path: 'api/tearups/graphql', method: RequestMethod.ALL });
}
}
Write a functional middleware as follow signature:
import { Request, Response, NextFunction } from 'express';
export function Logger(req: Request, res: Response, next: NextFunction) {
console.log(`Request...`, req.session.user);
next();
};
Or, a class-based middleware as:
#Injectable()
export class Logger implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log('Request...', req.session.user);
next();
}
}
Now apply the middleware as follows:
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(Logger)
.forRoutes(CatsController);
}
}

NestJs Eventbridge Lambda function

I have a system writed in using NestJs and serverless framework were each endpoint is a lambda function on aws. One of the functions is not an endpoint, but a trigger from AWS eventbridge. As this function is not an endpoint it cannot be included on a NestJs module since it have to be exported separatelly. My problem is that when the event comes to Eventbridge and triggers the lambda I have to call a NestJs service but I'm not able to do this, since the lambda function is outside NestJs environment. Is that a way for me to call a NestJs service from outside the module?
Here is the serverless framework configs
functions:
function 1(NestJs controller):
handler: src/lambda.handler
events:
- http:
cors: true
method: post
path: entrypoint for function 1
Function 2 (External from NestJs modules):
handler: path to lambda function
events:
- eventBridge:
eventBus: eventbus name
pattern:
source:
- source
Currently I'm using axios to call another NestJs endpoint to just pass the received payload. As you can see on the lambda function file:
import { Context, Handler } from 'aws-lambda'
import axios from 'axios'
export const handler: Handler = async (event: any, context: Context) => {
return await axios
.post(
'lambda function production url',
event.detail
)
.then((data) => {
console.log('data', data)
return data
})
.catch((error) => {
console.log('error', error)
return error
})
}
Here is the controller of lambda function 1
import { Body, Controller, Post } from '#nestjs/common'
import { MyService } from './enrichment.service'
#Controller('function1')
export class EnrichmentController {
constructor(private readonly myService: MyService) {}
#Post('entrypoint')
sendForm(#Body() body) {
return this.myService.start(body)
}
}
and here is the service
import { forwardRef, Inject, Injectable } from '#nestjs/common'
import { EventbridgeService } from '../eventbridge/eventbridge.service'
import { CampaignsService } from '../campaigns/campaigns.service'
import { UploadedDataService } from '../uploaded-data/uploaded-data.service'
#Injectable()
export class MyService {
constructor(
private readonly anotherService: AnotherService,
) {}
async start(body) {
return this.anotherService.updateData(body)
}
}
The question is: Is that a way to call all this NestJs structure from the function file, since it is outside NestJs modules and since the trigger for this function is not an http request but a trigger from Eventbridge? Thank you so much.
You can use a "Standalone" Nest application and pass the event data directly to MyService
You can use NEstJs standalone app, and make your handler like this
export const checkDeletion: Handler = async (event: any, context: Context) => {
async function bootstrap() {
const app = await NestFactory.createApplicationContext(AppModule);
await app
.select(SchedulerModule)
.get(SchedulerService, { strict: true })
.runScheduler();
}
await bootstrap();
};
After that call your handler from serverless.yaml like
functions:
followup-emails:
environment:
STAGE: ${opt:stage}
name: followup-emails-${opt:stage}
handler: src/lambda.checkDeletion
events:
- schedule: rate(1 day)

using fastify plugin inside a fastify plugin

According the documentation creating a plugin with fastify-plugin will not encapsulate and add the plugin content to the "global" fastify scope.
including the dbconnector plugin inside the db plugin doesn't add the inner plugin into the fastify scope.
works
server.js
fastify.register(import("./plugins/dbconnector.mjs"));
fastify.register(import("./plugins/db.mjs"), { prefix: "/db" });
doesn't
server.js
fastify.register(import("./plugins/db.mjs"), { prefix: "/db" });
plugins/db.mjs:
import fastifyPlugin from "fastify-plugin";
async function plugin(fastify, opts) {
fastify.register(import("./plugins/dbconnector.mjs"));
...
dbconnector.mjs (default documentation example)
import fastifyPlugin from "fastify-plugin";
async function dbConnector(fastify, options) {
fastify.register(import("fastify-mongodb"), {
url: "mongodb://...",
});
}
export default fastifyPlugin(dbConnector);

How to Ignore a specific route logging using Fastify in NestJs?

I want to ignore or change the logLevel of a route in my NestJs application using Fastify.
This is how I do it normally in Fastify application. Here I am changing the /health route logLevel to error so that it will only log when there is an error in health.
server.get('/health', { logLevel: 'error' }, async (request, reply) => {
if (mongoose.connection.readyState === 1) {
reply.code(200).send()
} else {
reply.code(500).send()
}
})
But This is my health controller in NestJs
#Get('health')
getHealth(): string {
return this.appService.getHealth()
}
And main.ts file.
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter({
logger: true
}),
)
I don't want to log the health route only and not the routes.
Please help in this regards.
To ignore/silent a specific route workaround in NestJS using Fastify.
We can use Fastify hook onRoute and change the log level for that route.
For example ignoring health route.
import fastify from 'fastify'
const fastifyInstance = fastify()
fastifyInstance.addHook('onRoute', opts => {
if (opts.path === '/health') {
opts.logLevel = 'silent'
}
})
If one is willing to use nestjs-pino can use something like this:
LoggerModule.forRoot({
pinoHttp: {
transport:
process.env.NODE_ENV !== 'production'
? { target: 'pino-pretty', options: { singleLine: true } }
: null,
customProps: () => ({ context: 'HTTP' }),
autoLogging: {
ignore: (req) => {
return ['/health/ping', '/swagger'].some((e) => req.originalUrl.includes(e))
},
},
},
}),

Resources