express-openapi-validator icon indicating copy to clipboard operation
express-openapi-validator copied to clipboard

Error hanlder not catching errors thrown in hanlder

Open RicardoE105 opened this issue 2 years ago • 1 comments

I declared an operation handler like this:

export = {
	createUser() {
		throw new Error(''error test);
	}
}

and registered an error handler like this:


	apiController.use((error: HttpError, req, res: express.Response) => {
		res.status(error.status || 500).json({
			message: error.message,
			errors: error.errors,
		});
	});

Why when I throw an error in the handler, it's not caught by the error handler? What I'm missing?

RicardoE105 avatar Apr 03 '22 23:04 RicardoE105

From Express docs:

For errors returned from asynchronous functions invoked by route handlers and middleware, you must pass them to the next() function, where Express will catch and process them.

As I found this too tedious to do in multiple places, I wrapped the default express-openapi-validator resolver in a little helper called express-async-handler. That did the trick!

import path from 'path'
import * as OpenApiValidator from 'express-openapi-validator'
import express, { ErrorRequestHandler } from 'express'
import asyncHandler from 'express-async-handler'
import { RouteMetadata } from 'express-openapi-validator/dist/framework/openapi.spec.loader'
import { OpenAPIV3 } from 'express-openapi-validator/dist/framework/types'

const app = express()
const apiSpec = path.join(__dirname, 'openapi.yml')

app.use(
    '/api',
    OpenApiValidator.middleware({
      apiSpec,
      operationHandlers: {
        basePath: __dirname,
        resolver: (
          basePath: string,
          route: RouteMetadata,
          apiDoc: OpenAPIV3.Document
        ) => {
          return asyncHandler(
            OpenApiValidator.resolvers.defaultResolver(basePath, route, apiDoc)
          )
        },
      },
    })
  )

// handle HTTP errors
app.use(((err, _req, res, next) => {
  if (!err.status) {
    return next(err)
  }

  res.status(err.status || 500).json({
    code: err.status,
    message: err.message,
    errors: err.errors,
  })
}) as ErrorRequestHandler)

// catch all unhandled errors without exposing sensitive data
app.use(((err, req, res, next) => {
  console.log(err)
  res.status(500).send({
    code: 500,
    message: 'Internal Server Error',
  })
}) as ErrorRequestHandler)

csuermann avatar Jun 10 '22 10:06 csuermann