error-middleware.ts 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import { Request, Response, NextFunction, ErrorRequestHandler } from "express";
  2. import { SchemaValidationError, SlonikError } from "slonik";
  3. import { ApiError } from "../exceptions/api-error.js";
  4. import { logger } from "../plugins/logger.js";
  5. import { ZodError } from "zod";
  6. import { UnexpectedError } from "#exceptions/unexpected-errors.js";
  7. const globalErrorHandler: ErrorRequestHandler = (
  8. err: unknown, // Тип ошибки здесь может быть широким, далее идут проверки instanceof
  9. req: Request,
  10. res: Response,
  11. next: NextFunction,
  12. ) => {
  13. if (!err) next();
  14. // Формируем объект с деталями запроса для логов
  15. const requestDetails = {
  16. method: req.method,
  17. url: req.originalUrl,
  18. ip: req.ip,
  19. body: req.body, // Осторожно: может содержать чувствительные данные, логируйте по необходимости
  20. query: req.query,
  21. };
  22. if (err instanceof ApiError) {
  23. logger.warn({
  24. message: `API Error: ${err.message}`,
  25. err: err,
  26. request: requestDetails,
  27. });
  28. res.status(err.status).json({ message: err.message, errors: err.errors });
  29. return;
  30. }
  31. if (err instanceof UnexpectedError) {
  32. logger.error({
  33. message: `Unexpected Error: ${err.message}`,
  34. err: err,
  35. request: requestDetails,
  36. });
  37. res
  38. .status(err.status)
  39. .json({ message: "Внутренняя ошибка сервера (схема БД)" });
  40. return;
  41. }
  42. if (err instanceof ZodError) {
  43. logger.error({
  44. message: "Ошибка валидации ZOD на сервере",
  45. err: err,
  46. request: requestDetails,
  47. });
  48. // TODO: Для клиента лучше отправлять обработанные ошибки, а не весь объект ZodError
  49. res.status(400).json({
  50. message: "Ошибка валидации ZOD",
  51. errors: err.flatten().fieldErrors,
  52. });
  53. return;
  54. }
  55. if (err instanceof SchemaValidationError) {
  56. logger.error({
  57. message: "Ошибка несоответствия схемы БД (Slonik SchemaValidationError)",
  58. err: err,
  59. request: requestDetails,
  60. });
  61. res.status(500).json({ message: "Внутренняя ошибка сервера (схема БД)" });
  62. return;
  63. }
  64. if (err instanceof SlonikError) {
  65. logger.error({
  66. message: "Ошибка запроса БД (SlonikError)",
  67. err: err,
  68. request: requestDetails,
  69. });
  70. res.status(500).json({ message: "Внутренняя ошибка сервера (запрос БД)" });
  71. return;
  72. }
  73. // Непредвиденная ошибка
  74. logger.error({
  75. message: "Непредвиденная ошибка сервера",
  76. err: err,
  77. request: requestDetails,
  78. });
  79. res.status(500).json({
  80. message: "Произошла непредвиденная ошибка. Пожалуйста, попробуйте позже.",
  81. });
  82. };
  83. export default globalErrorHandler;