error-sender.js 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import {inspect} from 'util';
  2. import getStatusMessage from 'statuses';
  3. import {getRequestPathname} from '../utils/index.js';
  4. import {DebuggableService} from '../debuggable-service.js';
  5. /**
  6. * Exposed error properties.
  7. *
  8. * @type {string[]}
  9. */
  10. export const EXPOSED_ERROR_PROPERTIES = ['code', 'details'];
  11. /**
  12. * Error sender.
  13. */
  14. export class ErrorSender extends DebuggableService {
  15. /**
  16. * Handle.
  17. *
  18. * @param {import('http').IncomingMessage} request
  19. * @param {import('http').ServerResponse} response
  20. * @param {Error} error
  21. * @returns {undefined}
  22. */
  23. send(request, response, error) {
  24. const debug = this.getDebuggerFor(this.send);
  25. let safeError = {};
  26. if (error) {
  27. if (typeof error === 'object') {
  28. safeError = error;
  29. } else {
  30. safeError = {message: String(error)};
  31. }
  32. }
  33. const statusCode = error.statusCode || error.status || 500;
  34. const body = {error: {}};
  35. if (safeError.message && typeof safeError.message === 'string') {
  36. body.error.message = safeError.message;
  37. } else {
  38. body.error.message = getStatusMessage(statusCode);
  39. }
  40. EXPOSED_ERROR_PROPERTIES.forEach(name => {
  41. if (name in safeError) body.error[name] = safeError[name];
  42. });
  43. const requestData = {
  44. url: request.url,
  45. method: request.method,
  46. headers: request.headers,
  47. };
  48. const inspectOptions = {
  49. showHidden: false,
  50. depth: null,
  51. colors: true,
  52. compact: false,
  53. };
  54. console.warn(inspect(requestData, inspectOptions));
  55. console.warn(inspect(body, inspectOptions));
  56. if (error.stack) {
  57. console.log(error.stack);
  58. } else {
  59. console.error(error);
  60. }
  61. response.statusCode = statusCode;
  62. response.setHeader('content-type', 'application/json; charset=utf-8');
  63. response.end(JSON.stringify(body, null, 2), 'utf-8');
  64. debug(
  65. 'The %s error was sent for the request %s %v.',
  66. statusCode,
  67. request.method,
  68. getRequestPathname(request),
  69. );
  70. }
  71. /**
  72. * Send 404.
  73. *
  74. * @param {import('http').IncomingMessage} request
  75. * @param {import('http').ServerResponse} response
  76. * @returns {undefined}
  77. */
  78. send404(request, response) {
  79. const debug = this.getDebuggerFor(this.send404);
  80. response.statusCode = 404;
  81. response.setHeader('content-type', 'text/plain; charset=utf-8');
  82. response.end('404 Not Found', 'utf-8');
  83. debug(
  84. 'The 404 error was sent for the request %s %v.',
  85. request.method,
  86. getRequestPathname(request),
  87. );
  88. }
  89. }