oapi-codegen icon indicating copy to clipboard operation
oapi-codegen copied to clipboard

Change ErrorHandler signature

Open illiafox opened this issue 2 years ago • 1 comments

Similar to #1143, but for fiber Original issue: #1144

Due to differences in gin and fiber error handling, ErrorHandler option was modified in order to support fiber. Message type was changed to support errors.Is/As

// ErrorHandler is called when there is an error in validation
type ErrorHandler func(c *fiber.Ctx, message error, statusCode int) error

Usage example:

fibermiddleware.OapiRequestValidatorWithOptions(swagger, &fibermiddleware.Options{
	ErrorHandler: func(c *fiber.Ctx, message error, statusCode int) error {
                return c.Status(statusCode).JSON(fiber.Map{
			"ok":    false,
			"error": message.Error(),
		}) // .JSON error is returned instead of being logged manually. Fiber middlewares could handle them
	},
})

illiafox avatar Jul 11 '23 09:07 illiafox

Since we return error explicitly, all errors wrappings fmt.Errorf("something happened: %s", err) must be replaced with fmt.Errorf("something happened: %w", err) in order to use errors.Is/As

switch e := err.(type) {
	case *openapi3filter.RequestError:
		// We've got a bad request
		// Split up the verbose error by lines and return the first one
		// openapi errors seem to be multi-line with a decent message on the first
		errorLines := strings.Split(e.Error(), "\n")
		return fmt.Errorf("error in openapi3filter.RequestError: %s", errorLines[0])
	case *openapi3filter.SecurityRequirementsError:
		return fmt.Errorf("error in openapi3filter.SecurityRequirementsError: %w", e)
	default:
		// This should never happen today, but if our upstream code changes,
		// we don't want to crash the server, so handle the unexpected error.
		return fmt.Errorf("error validating request: %w", err)
	}
}

So that we can determine in ErrorHandler whether error is BadRequest or Unauthorized

fibermiddleware.OapiRequestValidatorWithOptions(&specCopy, &fibermiddleware.Options{
	ErrorHandler: func(c *fiber.Ctx, message error, statusCode int) error {
		var securityRequirementsError *openapi3filter.SecurityRequirementsError
		if errors.As(message, &securityRequirementsError) {
			return api.SendUnauthorizedError(c, securityRequirementsError)
		}
		var requestError *openapi3filter.RequestError
		if errors.As(message, &requestError) {
			return api.SendBadRequestException(c, requestError)
		}
			
		return api.SendInternalError(c, message)
	},

illiafox avatar Jul 23 '23 14:07 illiafox

Thank you for this, and sorry it's taken so long for us to get to it - as part of https://github.com/oapi-codegen/nethttp-middleware/pull/35 we're looking at what a "better" OpenAPI validation middleware's error handling would look like and once that's merged, we'll look at pulling that into each of the separate middleware packages as needed

jamietanna avatar Apr 24 '25 08:04 jamietanna