From 382a42d4393a1b457620eb5fb50fc7805e007624 Mon Sep 17 00:00:00 2001 From: Stephan <57194608+stephan418@users.noreply.github.com> Date: Wed, 27 Apr 2022 15:30:55 +0200 Subject: [PATCH] Add basic error handling + Add express-async-errors package to handle async errors + Add ForwaradableError class (Base class for all project-specific errors) + Add defaultErrorHandler middleware which handles errors and sends info to the client --- package.json | 1 + src/Middleware/error/ForwardableError.ts | 16 +++++++++++ src/Middleware/error/handler.ts | 36 ++++++++++++++++++++++++ src/app.ts | 7 +++++ 4 files changed, 60 insertions(+) create mode 100644 src/Middleware/error/ForwardableError.ts create mode 100644 src/Middleware/error/handler.ts diff --git a/package.json b/package.json index 4166d94..9bbdaf3 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "argon2": "^0.28.2", "dotenv": "^10.0.0", "express": "^4.17.1", + "express-async-errors": "^3.1.1", "jsonwebtoken": "^8.5.1", "nodemailer": "^6.7.0", "redis": "^3.1.2" diff --git a/src/Middleware/error/ForwardableError.ts b/src/Middleware/error/ForwardableError.ts new file mode 100644 index 0000000..04bc5e1 --- /dev/null +++ b/src/Middleware/error/ForwardableError.ts @@ -0,0 +1,16 @@ +export default class ForwardableError extends Error { + // If in different context + private readonly __id = "CUSTOM_ERROR"; + + public readonly status: number; + + constructor(status: number, message: string) { + super(message); + + this.status = status; + } + + static isForwardableError(error: any): error is ForwardableError { + return error.__id === "CUSTOM_ERROR"; + } +} diff --git a/src/Middleware/error/handler.ts b/src/Middleware/error/handler.ts new file mode 100644 index 0000000..d182f19 --- /dev/null +++ b/src/Middleware/error/handler.ts @@ -0,0 +1,36 @@ +import { PrismaClientUnknownRequestError } from "@prisma/client/runtime"; +import { NextFunction, Request, Response } from "express"; +import ForwardableError from "./ForwardableError"; + +const env = process.env.NODE_ENV || "production"; + +export default function defaultErrorHandler(err: any, req: Request, res: Response, next: NextFunction) { + if (ForwardableError.isForwardableError(err)) { + return res.status(err.status).json({ + type: "error", + payload: { + message: err.message, + ...(env === "development" + ? { + stack: err.stack, + } + : {}), + }, + }); + } + + if (err instanceof PrismaClientUnknownRequestError) { + return res.status(404).json({ + type: "error", + payload: { + message: "An unknown error occured. This could be due to malformed IDs", + ...(env === "development" + ? { + prisma: err.message, + stack: err.stack, + } + : {}), + }, + }); + } +} diff --git a/src/app.ts b/src/app.ts index bb3b56b..83e28d1 100644 --- a/src/app.ts +++ b/src/app.ts @@ -6,6 +6,10 @@ import argon2 from "argon2"; import adminRouter from "./Routes/admin.routes"; import organisationRouter from "./Routes/organisation.routes"; import groupRouter from "./Routes/group.routes"; +import defaultErrorHandler from "./Middleware/error/handler"; + +// Set up async error handling +require("express-async-errors"); require("dotenv").config(); // Load dotenv config @@ -52,6 +56,9 @@ async function main() { app.use("/api/groups", groupRouter); + // Error handling + app.use(defaultErrorHandler); + app.listen(process.env.PORT, () => { console.log(`Listening on Port: ${process.env.PORT}`); });