File size: 1,404 Bytes
e8c33fa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
const { env } = require('../configs/env');
const { logError } = require('./errorLogger');

const HTTP_CODE_MAP = {
  400: 'BAD_REQUEST',
  401: 'UNAUTHORIZED',
  403: 'FORBIDDEN',
  404: 'NOT_FOUND',
  409: 'CONFLICT',
  413: 'PAYLOAD_TOO_LARGE',
  422: 'UNPROCESSABLE_ENTITY',
  429: 'RATE_LIMIT_EXCEEDED',
  503: 'SERVICE_UNAVAILABLE',
};

const getCode = (statusCode) =>
  HTTP_CODE_MAP[statusCode] || (statusCode >= 500 ? 'INTERNAL_SERVER_ERROR' : 'REQUEST_FAILED');

const asyncController = (handler, { defaultStatus = 500, onError } = {}) => async (req, res, next) => {
  try {
    await handler(req, res, next);
  } catch (err) {
    if (res.headersSent) {
      return next(err);
    }

    if (typeof onError === 'function') {
      const handled = await onError(err, req, res, next);
      if (handled) return;
    }

    const statusCode =
      Number.isInteger(err?.statusCode) && err.statusCode >= 400
        ? err.statusCode
        : res.statusCode >= 400
          ? res.statusCode
          : defaultStatus;

    const code = getCode(statusCode);

    if (statusCode >= 500) {
      logError(err, { req, statusCode, code });
    }

    const message = env.isProduction && statusCode >= 500
      ? 'An internal error occurred'
      : (err.message || 'Request failed');

    res.status(statusCode).json({ success: false, message, code });
  }
};

module.exports = { asyncController };