Tried to improve debugging when an express middleware is wrapped to auto-handle errors of an asnync
function.
Turns out the below reads a bit better than a return Promise.catch()
implementation, but still, once we reach the central express error handler, the line of the wrapped function that caused the error isn't included.
'use strict'
function asyncify(fn) {
async function asyncifyWrap(req, res, next) {
try {
return await fn.apply(null, arguments)
} catch (err) {
next(err)
}
}
return asyncifyWrap
}
module.exports = asyncify
'use strict'
const express = require('express')
const helmet = require('helmet')
const { transports, Logger } = require('winston')
const morgan = require('morgan')
const request = require('request-promise-native')
const asyncify = require('./asyncify')
//
// Logging Setup
//
const consoleTransport = new transports.Console({
level : 'debug'
, handleExceptions : false
, colorize : true
, timestamp : true
, prettyPrint : true
})
function devLogger() {
const transports = [ consoleTransport ]
return new Logger({ transports, exitOnError: true })
}
function morganMiddleware(logger) {
return function morganHandler(tokens, req, res) {
const { method, url, status } = tokens
logger.info(
`${method(req, res)} ${url(req, res)} ${status(req, res)} - ` +
`${tokens['response-time'](req, res)} ms`
)
return null
}
}
const log = devLogger()
//
// App Setup
//
const PORT = process.env.PORT || 4444
const app = express()
app
.use(helmet())
.use(morgan(morganMiddleware(log)))
.get('/cause-error-wrap', asyncify(async function causeError(req, res) {
// Super important to name our async function here as otherwise debugging becomes
// very hard
const result = await request(`h://www.google.com/search?q=node`)
res.status(200).send('Surprisingly all good ' + result)
}))
.get('/cause-error', async function causeError(req, res, next) {
// Manually wrapping async/await constructs inside try/catch as this improves debugging
// compared to using wrapper functions greatly.
try {
const result = await request(`h://www.google.com/search?q=node`)
res.status(200).send('Surprisingly all good ' + result)
} catch (err) {
next(err)
}
})
.use((err, req, res, next) => {
log.error(err.toString())
log.debug(err.stack)
res.status(500).send(err.message)
})
.listen(PORT)