Handling with more than one useGlobal on Nestjs - nestjs

My question is quite simple, I'm trying to use GlobalFilters with GlobalPipes, the pipes I use for validating the payload sent to the API and the filters are responsible to handle the error during execution of API calls. But when the pipe tries to validate and returns a negative result, the filter is replacing the returned pipe.
main.ts
const app = await NestFactory.create(MainModule);
app.useGlobalFilters(new PaymentGeneratorExceptionFilter())
app.useGlobalPipes(new ValidationPipe());
app.setGlobalPrefix('v1');
const port = process.env.PORT || 8080;
await app.listen(port);
What should I do in this case ? Is there a way to make the filter not catch the pipe errors?

The problem is the ValidationPipe extends a HttpException and my PaymentGeneratorExceptionFilter catches a HttpException, so this is why the GlobalFilter changes the return of the GlobalPipe.
Just a misunderstanding on my part.

Related

Concurrency with fs.writeFileSync using NodeJS and ExpressJS

I have the following code written with NodeJS and ExpressJS:
const express = require("express");
const fs = require("fs");
const bodyParser = require("body-parser");
const jsonParser = bodyParser.json();
const hostname = "127.0.0.1";
let port = 3001;
const app = express();
app.use(express.static(__dirname + "/answers"));
const answersPath = __dirname + "/answers/answers.json";
app.patch("/new/answer", jsonParser, function (req, res) {
try {
const questionId = req.body.questionId;
const answer = req.body.answer;
const answersJson = JSON.parse(fs.readFileSync(`${answersPath}`, "utf8"));
if (answersJson[questionId]) {
answersJson[questionId] = [...answersJson[questionId], answer];
} else {
answersJson[questionId] = [answer];
}
fs.writeFileSync(`${answersPath}`, JSON.stringify(answersJson));
res.sendStatus(200);
} catch (e) {
console.error(e);
res.sendStatus(500);
}
});
app.listen(port);
console.log(`Server running at http://${hostname}:${port}/`);
What it basically does, it has an endpoint (/new/question), on which it receives as a JSON format, a question and an answer.
If the question exists already in the answers.json file, it adds the new answer to the list of answers for that question. If not, it creates a new question with a list of the answer.
Now, I've read the following article: https://www.geeksforgeeks.org/how-to-handle-concurrency-in-node-js/
And what I understood from here, is that even though the endpoint would get called at the same time by two clients, both of the responses will be saved, one after the other - one of them will wait for the other one, i.e. the file will not get overwritten.
So my question is, is this true? NodeJS deals with concurrency on its own, or do I need to implement something to prevent this from happening?
Thank you, and sorry if this is a dumb question 😞.
Although readFileSync() and writeFileSync() might do what you want to achieve, you should avoid using synchronous functions in Node.js.
Synchronous functions will block the entire Node.js process, not just the a single Express route. This means your server will become unresponsive while reading or writing the file. This will become an issue if the file gets bigger.
Instead of using a file, you could keep the data only in memory. If you need to persist the data between server restarts, you can read it when the server starts and write it when the server stops. In this case it might be okay to use synchronous functions.

Nestjs wss handleConnection(socket) socket.handshake is undefined and cannot access headers to authenticate

I have a Nestjs gateway where I'm trying to run authorization logic depending on values from the headers but wherever I'm trying to access the handshake it always returns 'undefined'
I'm also trying this over SSL which might be making a difference.
main.ts:
import { WsAdapter } from "#nestjs/platform-ws";
app = await NestFactory.create(UserMicroserviceModule, {
httpsOptions: {
key: get_ssl("key"),
cert: get_ssl("cert"),
},
});
app.useWebSocketAdapter(new WsAdapter(app));
await app.listen(process.env.PORT || 443);
gateway.ts:
#UseGuards(SessionGuard)
#WebSocketGateway({ path: "/user" })
export class UserMicroserviceGateway implements OnGatewayConnection {
handleConnection(socket) {
socket.handshake // <== undefined
}
session.guard.ts:
const socket_cookie: any = context.switchToWs().getClient().handshake; // <== undefined
And also, although I've addeded the session guard on the whole gateway --- the guard does not trigger for handleConnection()
Guards and other decorators don't work for the handleConnection() method in nestjs currently and the handshake isn't a concept that exists on the vanilla socket but more of a socket.io thing, so I just switched to using that and manually ran the actions needed for verifications inside the handleConnection() method.

How to remove authentication for introspection query in Graphql

so may be this is very basic question so please bear with me. Let me explain what I am doing and what I really need.
EXPLANATION
I have created a graphql server by using ApolloGraphql (apollo-server-express npm module).
Here is the code snippet to give you an idea.
api.js
import express from 'express'
import rootSchema from './root-schema'
.... // some extra code
app = express.router()
app.use(jwtaAuthenticator) // --> this code authenticates Authorization header
.... // some more middleware's added
const graphQLServer = new ApolloServer({
schema: rootSchema, // --> this is root schema object
context: context => context,
introspection: true,
})
graphQLServer.applyMiddleware({ app, path: '/graphql' })
server.js
import http from 'http'
import express from 'express'
import apiRouter from './api' // --> the above file
const app = express()
app.use([some middlewares])
app.use('/', apiRouter)
....
....
export async function init () {
try {
const httpServer = http.createServer(app)
httpServer
.listen(PORT)
.on('error', (err) => { setTimeout(() => process.exit(1), 5000) })
} catch (err) {
setTimeout(() => process.exit(1), 5000)
}
console.log('Server started --- ', PORT)
}
export default app
index.js
require('babel-core')
require('babel-polyfill')
require = require('esm')(module/* , options */)
const server = require('./server.js') // --> the above file
server.init()
PROBLEM STATEMENT
I am using node index.js to start the app. So, the app is expecting Authorization header (JWT token) to be present all the times, even for the introspection query. But this is not what I want, I want that introspection query will be resolvable even without the token. So that anyone can see the documentation.
Please shed some light and please guide what is the best approach to do so. Happy coding :)
.startsWith('query Introspection') is insecure because any query can be named Introspection.
The better approach is to check the whole query.
First import graphql and prepare introspection query string:
const { parse, print, getIntrospectionQuery } = require('graphql');
// format introspection query same way as apollo tooling do
const introspectionQuery = print(parse(getIntrospectionQuery()));
Then in Apollo Server configuration check query:
context: ({ req }) => {
// allow introspection query
if (req.body.query === introspectionQuery) {
return {};
}
// continue
}
There's a ton of different ways to handle authorization in GraphQL, as illustrated in the docs:
Adding middleware for express (or some other framework like hapi or koa)
Checking for authorization inside individual resolvers
Checking for authorization inside your data models
Utilizing custom directives
Adding express middleware is great for preventing unauthorized access to your entire schema. If you want to allow unauthenticated access to some fields but not others, it's generally recommended you move your authorization logic from the framework layer to the GraphQL or data model layer using one of the methods above.
So finally I found the solution and here is what I did.
Let me first tell you that there were 2 middle-wares added on base path. Like this:
app //--> this is express.Router()
.use(jwtMw) // ---> these are middlewares
.use(otherMw)
The jwtMw is the one that checks the authentication of the user, and since even introspection query comes under this MW, it used to authenticate that as well. So, after some research I found this solution:
jwtMw.js
function addJWTMeta (req, res, next) {
// we can check for null OR undefined and all, then check for query Introspection, with better condition like with ignore case
if (req.body.query.trim().startsWith('query Introspection')) {
req.isIntrospection = true
return next()
}
...
...
// ---> extra code to do authentication of the USER based on the Authorization header
}
export default addJWTMeta
otherMw.js
function otherMw (req, res, next) {
if (req.isIntrospection) return next()
...
...
// ---> extra code to do some other context creation
}
export default otherMw
So here in jwtMw.js we are checking that if the query is Introspection just add a variable in req object and move forward, and in next middleware after the jwtMw.js whosoever wants to check for introspection query just check for that variable (isIntrospection, in this case) and if it is present and is true, please move on. We can add this code and scale to every middleware that if req.isIntrospection is there just carry on or do the actual processing otherwise.
Happy coding :)

How do I prevent node from logging an exception to the console in my NextJS/Express app?

I have an Express application that runs a blog in a NextJS app, very similar to the example in their repo
I have set it up so that my app runs a query to fetch a blog article, and if the result is empty it throws a NotFoundException.
I catch this exception in my NextJS _error.js file, which is similar to a React error boundary, where I route the user to my 404 page. This part works fine.
The problem I'm having is that this exception is logged to the node console even though I'm not logging it when catching the exception. This pollutes our company's logging software with all our 404's
Is there some node/express setting I'm missing here that prevents the logging of exceptions? Here's my Express process error handler:
process.on('unhandledRejection', (reason, promise) =>
console.error(`Unhandled Rejection at: ${promise}.\nreason: ${reason.stack || reason}`));
I know there is a log there, but the format of the one I want to eliminate is different to this, so I'm confident this is not the source.
I won't pretend to know what's going on, but my best guess is that next.js is logging the error somewhere. I did some digging and it appears there's an error logger in the server code that will log on errors unless a quiet property is set on the server:
https://github.com/zeit/next.js/blob/canary/packages/next-server/server/next-server.ts#L105:
return this.run(req, res, parsedUrl)
.catch((err) => {
this.logError(err)
res.statusCode = 500
res.end('Internal Server Error')
})
Here's the sig and body for the logError function:
private logError(...args: any): void {
if (this.quiet) return
// tslint:disable-next-line
console.error(...args)
}
If you look at the documentation for using the next API with a custom server, it notes the following options object properties that can be passed to the constructor:
The next API is as follows:
next(opts: object)
Supported options:
dev (bool) whether to launch Next.js in dev mode - default false
dir (string) where the Next project is located - default '.'
quiet (bool) Hide error messages containing server information - default false
conf (object) the same object you would use in next.config.js - default {}
When constructing the next object, try passing quiet as true to see if it resolves your issue:
const express = require('express')
const next = require('next')
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev, quiet: true })
const handle = app.getRequestHandler()
The docs also mentions errors are logged in non-production environments (identified when process.env.NODE_ENV !== 'production'), so I would also check to ensure you're setting NODE_ENV to 'production' when starting your application:
NODE_ENV=production node server.js
I hope this helps!
In express you can setup an ErrorMiddleware.
After all your routes declaration, put
server.use(function(req, res, next) {
handler(req, res).catch(e => {
// use rejected promise to forward error to next express middleware
next(e)
})
});
Like this, when you reject a Promise, next(e) will send your error to next middleware. I usually setup a middleware where i send error, and then i manage all errors in one single function (based on statusCode error,...).

NodeJS express framework reads the same event multiple times

I'm working with a service (WSO2CEP) that sends events to a node js program that I developed, let's call it receiver.js, and then it stores these events in a mongo db. The comunication between WSO2CEP and receiver.js is done through a HTTP connection. The problem I'm facing on is that when the WSO2 sends an event, the receiver.js caputres it and stores it in the db, and after a few seconds/minutes, it detects that a new events has arrived, which is not true, and stores it again in the db. This second event is identical to the first one.
When I saw that I thought that the problem was that the WSO2 was sending the same event multiple times, but I've debug it an I'm 100% sure that only one events is being sent, so the problem seems to be the HTTP connection.
The HTTP connection is being handled by the receiver.js acting as a server and WSO2 as a client, which sends the events through HTTP post request. The http server implementation in receiver.js is done with the "express" framework. As it can be seen in below code chunk.
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const EventEmitter = require('events');
const port = Whatever;
module.exports = class WSO2Server extends EventEmitter {
constructor () {
super();
const app = express();
app.use(bodyParser.json()); // to support JSON-encoded bodies
app.route('/Whatever').post( (req, res) => {
let event = req.body;
this.emit('event', event);
});
this.server = app.listen(port);
}
destroy () {
this.server.close();
}
}
I suspect that the events are being stored in a queu (or similar) and are being retransmitted every so often. Any idea about that? Thank you
Looking at your code, I can't see you using the response object at all. After you've called this.emit('event', event); you should call something like res.status(201).end(); which will dispatch a HTTP Status 201 back to the calling client.
Because you're not setting any information on the response object, your application is hanging and not making a response to the HTTP call. Thus something like nginx or apache is re-issuing the request to your application after a specific timeout.
If you explicitly create the response with something res.status(201).end(); then your request will end correctly and a duplicate call will not be made.

Resources