Search code examples
node.jstypescriptexpresserror-handling

My error handler return error in console not in reponser, why?


This is my first question, I'm sorry if I did something wrong and I'm open to suggestions to ask better questions.

My error handler dont show the message in response, the message show in console app and crash my app

I'm using nodejs with express and typescript

Here's part of my code for context.

I notice that when I remove async it works correctly and I release the unresponsive error

My request have a wrong email to test throw new UnauthorizedError('Invalid credentials')

My errorHandlerMiddleware

import { Request, Response, NextFunction } from 'express'
import { ApiError } from '../helper/ApiError'

export default function errorHandlerMiddleware(
  err: Error & Partial<ApiError>,
  req: Request,
  res: Response,
  next: NextFunction
) {
  const statusCode = err.statusCode ?? 500
  const message = err.statusCode
    ? err.message ?? 'Internal server Error!'
    : 'Internal server Error!'

  return res.status(statusCode).json({ message })
}

My helper with error list

export class ApiError extends Error {
  public readonly statusCode: number

  constructor(message: string, statusCode: number) {
    super(message)
    this.statusCode = statusCode
  }
}

export class BadRequestError extends ApiError {
  constructor(message: string) {
    super(message, 400)
  }
}

export class UnauthorizedError extends ApiError {
  constructor(message: string) {
    super(message, 401)
  }
}

export class ForbiddenError extends ApiError {
  constructor(message: string) {
    super(message, 403)
  }
}

export class NotFoundError extends ApiError {
  constructor(message: string) {
    super(message, 404)
  }
}

export class ConflictError extends ApiError {
  constructor(message: string) {
    super(message, 409)
  }
}

export class InternalServerError extends ApiError {
  constructor(message: string) {
    super(message, 500)
  }
}

My authController with the exception

import { Request, Response } from 'express'
import { UnauthorizedError } from '../helper/ApiError'
import UserRepository from '../repositories/UserRepository'
import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'
import dotenv from 'dotenv'

dotenv.config()

class AuthController {
  async auth(req: Request, res: Response): Promise<Response> {

    const { email, password } = req.body
    const user = await UserRepository.findUserByEmail(email)

    if (!user) {
      throw new UnauthorizedError('Invalid credentials')
    }

    const isValidPassword = await bcrypt.compare(password, user.password)

    if (!isValidPassword) {
      throw new UnauthorizedError('Invalid credentials')
    }

    const token = jwt.sign(
      { id: user.id },
      process.env.JWT_SECRET || 'secret',
      { expiresIn: '1d' }
    )

    return res.status(200).json({
      user: {
        name: user.name,
        email: user.email
      },
      token
    })
  }
}
export default new AuthController()

server.js

import 'express-async-error'
import { app } from './app'
import dotenv from 'dotenv'
import { AppDataSource } from './database/data-source'

import errorHandlerMiddleware from './app/middlewares/errorHandlerMiddleware'

dotenv.config()

const port = process.env.PORT || 3000

AppDataSource.initialize().then(async () => {
  console.log('database is running')
  app.use(errorHandlerMiddleware)
  app.listen(port, () => {
    console.log(`server is running in  http://localhost:${port}`)
  })
})

my index route

import { Router } from 'express'

import AuthRouter from './authRoutes'
import UserRouter from './userRoutes'

const router = Router()

router.get('/', (_req, res) => {
  res.send('hi, iam alive!')
})

router.get('/test', (_req, res) => {
  throw new Error('error...')
})

router.use('/auth', AuthRouter)
router.use('/user', UserRouter)

export default router


My auth route

import { Router } from 'express'

import AuthController from '../controllers/AuthController'

const router = Router()

router.post('/', AuthController.auth)

export default router

My console return

database is running
server is running in  http://localhost:3000
C:\workspace\project\src\app\controllers\AuthController.ts:17
      throw new UnauthorizedError('Invalid credentials')
            ^
UnauthorizedError: Invalid credentials
    at auth (C:\workspace\project\src\app\controllers\AuthController.ts:17:13)
    at processTicksAndRejections (node:internal/process/task_queues:95:5) {
  statusCode: 401
}
[nodemon] app crashed - waiting for file changes before starting...

I have no ideia..

I tried use the express-async-error but nothing happing My error handler works in other simple route example

router.get('/testError', (_req, res) => { throw new Error('error...') })

In this case the error occorred in response...

reponse

{
    "message": "Internal server Error!"
}

Solution

  • Seems you have a typo in one of your server.ts import statements, it should be express-async-errors, rather than express-async-error.