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

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,...).

Related

Firebase Cloud Function Keep return "Request failed with status code 404"

I created some functions in firebase cloud functions, but all of them are works. But i have a new function which is not work properly. I don't know why but i think it has same pattern with others.
this is my code:
const functions = require('firebase-functions');
const appVideo = express();
const cors = require('cors')({ origin: true });
appVideo.use(cors);
appVideo.get('/update-video', async(req, res) => {
console.log('updateStatusVideo idCourse', req.query.idCourse, ' idMateri: ', req.query.idMateri, ' idVideo:', req.query.idVideo);
res.status(200).send('Oke')
})
exports.video = functions.https.onRequest(appVideo)
I often call partial deploy like
firebase deploy --only functions:video. But when i execute the functions https through browser it often return
Request failed with status code 404
other weird things is when i inspect the browser and switch to console, i found
Failed to load resource: the server responded with a status of 500 ()
this is the url of function in firebase:
https://us-central1-my-apps.cloudfunctions.net/video [modified for confidential]
Please help
When you export this line:
exports.video = functions.https.onRequest(appVideo);
You define a Cloud Function called video that is deployed as https://us-central1-PROJECT_ID.cloudfunctions.net/video where PROJECT_ID is whatever your Firebase Project ID is.
Because you use a express application for this exported function, any URL that is handled must first start with https://us-central1-PROJECT_ID.cloudfunctions.net/video (the BASE_URL).
This line:
appVideo.get('/update-video', ...)
attaches a listener to BASE_URL/update-video, which becomes https://us-central1-PROJECT_ID.cloudfunctions.net/video/update-video.
If you want to use just https://us-central1-PROJECT_ID.cloudfunctions.net/video as-is, you'll need to change to using
appVideo.get('/', ...)
If you want to use just https://us-central1-PROJECT_ID.cloudfunctions.net/update-video, you'll need to change to using
appVideo.get('/', ...)
and
exports.update = {};
exports.update.video = functions.https.onRequest(appVideo);
// "update.video" is deployed as "update-video"
Note: This last part abuses deploying groups to get the desired URL

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 :)

Unhandled promise rejection warning in Webpack, for Vue.js

In an attempt to add a "server-side" state machine service to a single page application of Vue.js (cli), I edited following lines in webpack-dev-server/lib/Server.js:
const app = this.app = new express(); // eslint-disable-line
var globalStore ={ numRequests : 0 };
// I added this by copy-pasting another app.all('/',..) request handler.
app.all('/compute', (req, res, next) => {
globalStore.numRequests++;
res.send("num request="+globalStore.numRequests);
return next();
});
then it gave this warning each time counter is incremented:
(node:12956) UnhandledPromiseRejectionWarning: Error
[ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the
client
Still, it increments the counter, returns it successfully everytime I visit {mydomainname}/compute. Everytime it gives same warning.
I guess I'm making a simple error but can't see. Project was produced by this command:
vue init webpack vueapp01
If I delete "return next" and "res.send ('invalid host header')" lines, no warning is produced. Do I have to call "return" here always?

exception Handling In Express JS

I am developing a rest api using express JS . I want to show several error such as route not found, data not found, validation error. I am using async await structure . I need to know how to manage several exception handling in Express JS . I search seveal website but not found exact way . Everywhere write to use nodeJS default exception . But i need it customize in REST API.
I need expert nodejs developer help . If anyone know best resource of express error handling please provide me link to learn this
1.Let for handling route not found error you can use the default route
app.all('/*', (req, res)=> res.status(404).send('Route Not Found'))
2.For handling response, you can set some predefined response in separate module and send all response from that module. Like
//response.js file
module.exports= {
ok : (res, data)=> res.status(200).send({data}),
error: (res, err)=> res.status(err.status).send({error})
}
3.For handling error you can make seperate error file where all error a set and create your error by those listed error. And you can do by try, catch
4.For validation, you can use middleware and or helper for handling validation.
5.Following are some node.js configuration link created by me, you can take reference from there
https://github.com/bapinmalakar/election-exitpoll-back (very simple, Github)
https://github.com/bapinmalakar/pt-backend (little complex, github)
You can log the error using middleware As below given example middleware we can catch the errors which are thrown across the application. Also, we can catch the promise rejections
const express = require("express");
const app = express();
app.use((err, req, res, next) => {
if (err) {
res.status(err.statusCode || 500).send(err);
console.error(err.stack);
next();
}
console.error(`Message :: ${err.message}
Url :: ${req.originalUrl}
Method :: ${req.method}
Ip :: ${req.ip}
Time :: ${(new Date()).toLocaleTimeString()}`);
});
For reference use this link. Click here

Angular 2 routing only works in ng serve but not nodemon

I'm currently developing angular 2 application. But i'm having a hard time understanding why my routing on works in ng serve and not in nodemon? I've tried out multiple method based on what i've research on but they dont really works like how i thought it would be. (Probably due to my poor understanding)
Method 1
Adding useHash: true in the app-routing.module.ts But this would cause all the URL to have # appear in it. And i'm thinking this is meant for debugging purposes right?
const routes = [
{ path: '', component: sampleComponent1 },
{ path: 'page2', component: sampleComponent2 }
];
#NgModule({
imports: [RouterModule.forRoot(routes, {useHash: true})],
exports: [RouterModule]
})
Method 2
Change app.js to render index whenever error is thrown. This method would not have # in URL but it will always return error like GET /page2 404 1.688 ms - 987 in my console.
app.use(function (err, req, res, next) {
// set locals, only providing error in development
console.log(err.message);
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
So as of now, I'm sticking more to method 2 as the URL does not show # in it, but i'm not sure if method 2 is the correct way to do it. Can someone help me out on this?
The reason this works in development with the Angular CLI is that all routes that don't exist get served as index.html
This allows your Angular application to handle all the routing regardless of what URL was actually requested. Once your application is started in the browser the Angular router (assuming that's what you're using) will read the route information and display the correct route to your user.
There are other answers on here that explain this solution as well depending upon your web server.

Resources