@sap/cds
Version:
SAP Cloud Application Programming Model - CDS for Node.js
49 lines (39 loc) • 2.24 kB
JavaScript
const cds = require('../..'), {i18n} = cds
const LOG = cds.log('error')
const internals = /\n +at .*(?:node_modules\/express|node:).*/gm
const is_test = typeof global.it === 'function'
const { STATUS_CODES } = require('http')
module.exports = () => {
/** @param {import('express').Response} res */
return function http_error (err, req, res, next) { // eslint-disable-line no-unused-vars
// In case of 401 require login if available by auth strategy
if (typeof err === 'number') err = { status: err, code: String(err), message: STATUS_CODES[err] }
if (err.code == 401 && req._login) return req._login()
// Shutdown on uncaught errors, which could be critical programming errors
if (!is_test && cds.env.server.shutdown_on_uncaught_errors)
if (cds.error.isSystemError(err))
return cds.shutdown(err)
// Prepare status and a serializable error object
let { statusCode:sc, status = sc || Number(err.code) || 500, message, toJSON, ...rest } = err // eslint-disable-line no-unused-vars
let error = { message, ...rest, __proto__:err } // toJSON is inherited from __proto__:err
res.status(status)
// Log the error, with cleansed stack trace
if (err.stack) Object.defineProperty (err, 'stack', { value: err.stack.replace (internals,'') })
const log = status < 500 ? LOG.warn : LOG.error
log (status, '-', error) // TODO: don't log validation errors as errors
// Already sent a response? => done
if (res.headersSent) return
// In case of 5xx errors in production don't reveal details to clients
let PROD = process.env.NODE_ENV === 'production' || process.env.CDS_ENV === 'prod'
if (PROD && status >= 500 && error.$sanitize !== false) error = {
message: i18n.messages.at(status, cds.context.locale) || 'Internal Server Error',
code: String(status), // toJSON is intentionally gone
}
// Errors can come with a custom $response() method to control how the
// error response shall be structured; default: { error: { ... } }
// E.g., SCIM doesn't wrap the error => err.$response = err => err
let response = err.$response?.call(error,error) || { error }
// Finally send the error response
return res.json (response)
}
}