I'm looking for code review on the following basic log/error middleware. The logging middleware uses logger.js
which has a bunch of methods like log.error()
(which makes a request out to error tracking service like Sentry).
The handleErrors
middleware is intended to handle any errors that occur in any of the api routes. So, for example, I have a route /api/users
and if an error occurs in that request, the catch
will execute and pass along the error to the handleErrors
middleware.
const getUsers = (req, res, next) => {
return apiHttpClient.get(req, '/api/users')
.then(users => res.status(HttpStatus.OK).json(users))
.catch(err => next(err));
};
The error middleware should create an error context for the client without exposing the specific error. So for example, if a 400 error occurs, the message sent to the browser would look like:
{
"message": "Bad Request",
"status": 400
}
But depending on if the NODE_ENV
is production, the logging middleware should log out the specific error:
{
"name":"Example",
"hostname":"",
"pid":18322,
"level":40,
"payload":{
"name":"BadRequest",
"message":"A specific error message",
"statusCode":400,
"errorCode":400
},
"msg":"400: A specific error message",
"time":"2017-10-22T15:26:06.824Z",
"v":0
}
Usage
express.js
const { logErrors, handleErrors } = require('./errorMiddleware');
// other middleware
// api routes
app.use(logErrors())
app.use(handleErrors());
errorMiddleware.js
const log = require('../../logger');
const HttpStatus = require('http-status-codes');
const isServerError = (statusCode) => {
return statusCode >= HttpStatus.INTERNAL_SERVER_ERROR;
};
const isProdEnv = (env) => {
return env === 'production';
};
const getStatusCode = (statusCode) => {
return statusCode || HttpStatus.INTERNAL_SERVER_ERROR;
};
const createErrorContext = (statusCode) => {
return {
message: HttpStatus.getStatusText(statusCode),
status: statusCode
};
};
const createErrorMessage = (err) => {
const statusCode = getStatusCode(err.statusCode);
return `${statusCode}: ${err.message}`;
};
const deleteErrorStack = (env, err) => {
if (isProdEnv(env)) delete err.stack;
};
const getLogLevel = (statusCode) => {
return isServerError(statusCode) ? 'error' : 'warn';
};
const logErrors = () => {
return (err, req, res, next) => {
const statusCode = getStatusCode(err.statusCode);
const logLevel = getLogLevel(statusCode);
const errMessage = createErrorMessage(err);
const extraData = req.path;
log[logLevel](errMessage, err, extraData);
next(err);
};
};
const handleErrors = () => {
return (err, req, res, next) => {
const statusCode = getStatusCode(err.statusCode);
const errorContext = createErrorContext(statusCode);
deleteErrorStack(req.app.get('env'), err);
res.status(statusCode).json(errorContext);
};
};
module.exports = {
logErrors: logErrors,
handleErrors: handleErrors
};