@m92/express-utils
Version:
Utility Module for Express Framework
132 lines (102 loc) • 3.55 kB
JavaScript
import context from 'express-http-context'
import { nanoid } from 'nanoid'
import { v4 as uuidv4 } from 'uuid'
import autoBind from 'auto-bind'
import { validationResult } from 'express-validator'
export default class Middleware {
constructor (CONFIG, CONSTANTS, thisExpressUtils) {
const { logger, CustomError, reqHandler, httpContext } = thisExpressUtils
const { asyncWrapper } = reqHandler
this.CONFIG = CONFIG
this.CONSTANTS = CONSTANTS
this.logger = logger
this.CustomError = CustomError
this.asyncWrapper = asyncWrapper
this.httpContext = httpContext
autoBind(this)
}
init (app) {
const { CONFIG } = this
app.use(context.middleware)
app.use(this.apiTagging)
if (CONFIG.LOGGER_REQ_RES_LOG_ENABLED) {
app.use(this.apiLogger)
}
}
apiTagging (request, response, next) {
const { CONFIG, CONSTANTS, httpContext } = this
_tagSessionId(CONFIG, CONSTANTS, request, response, httpContext)
_tagRequestId(CONFIG, CONSTANTS, request, response, httpContext)
process.nextTick(next)
}
apiLogger (request, response, next) {
const { logger, httpContext } = this
const { ReqResLog } = logger
httpContext.setReqResBodyLog(true)
request.timestamp = Date.now()
response.on('finish', () => {
const reqResLog = new ReqResLog(request, response)
logger._dispatch(reqResLog)
})
process.nextTick(next)
}
requestValidator (validationFunction, errorMap) {
const { CustomError, asyncWrapper } = this
const validate = async (request, response, next) => {
const validations = validationFunction()
await Promise.all(validations.map(validation => validation.run(request)))
const errors = validationResult(request)
if (errors.isEmpty()) {
return next()
}
const extractedErrors = errors.array().reduce((output, error) => {
const { param, msg } = error
const currentValue = output[param]
if (!currentValue) { output[param] = [] }
output[param].push(msg)
return output
}, {})
throw new CustomError(extractedErrors, errorMap)
}
return asyncWrapper(validate)
}
disableReqResBodyLogging (request, response, next) {
const { httpContext } = this
httpContext.setReqResBodyLog(false)
process.nextTick(next)
}
}
// --------- API Tagging -------------------------------------------------------
function _extractFromHeader (headers = {}, key = '') {
let value = headers[key] || ''
value = value || headers[key.toLowerCase()] || ''
return value
}
function _tagSessionId (CONFIG, CONSTANTS, request, response, httpContext) {
const {
SESSION_ID_HEADER_KEY,
SESSION_ID_PROP
} = CONSTANTS
const { headers = {} } = request
const sessionId = _extractFromHeader(headers, SESSION_ID_HEADER_KEY) ||
httpContext.getSessionId() ||
nanoid()
httpContext.setSessionId(sessionId)
request[SESSION_ID_PROP] = sessionId
response[SESSION_ID_PROP] = sessionId
}
function _tagRequestId (CONFIG, CONSTANTS, request, response, httpContext) {
const {
REQUEST_ID_HEADER_KEY,
REQUEST_ID_PROP
} = CONSTANTS
const { headers = {} } = request
const sessionId = _extractFromHeader(headers, REQUEST_ID_HEADER_KEY) ||
httpContext.getRequestId() ||
uuidv4()
httpContext.setRequestId(sessionId)
request[REQUEST_ID_PROP] = sessionId
response[REQUEST_ID_PROP] = sessionId
}
// -----------------------------------------------------------------------------