Error handling
In general
Whenever a middleware or handler returns a value which implements error
interface, the execution flow is frozen and appropriate error handler is called.
To create an error handler, you need to implement a function with the following rules:
- Takes exactly one argument, which type implements
error
interface. - Can not return an
error
. - Values returned from error handler behave similarly like from a middleware.
- Should return a response, because the handler might not be called.
The simplest example can look like:
Register it in the router:
Now every returned error will be handled by our custom error handler.
Default handler
If you don't register any error handler, the default one will be called, which gracefully handles the following errors:
*json.SyntaxError
*json.UnmarshalTypeError
validator.ValidationErrors
*gnext.NotFound
You probably noticed, that in documentation of your API, next to your response, there are error responses. They come from the default error handler definition which returns the following response struct:
type DefaultErrorResponse struct {
ErrorResponse `default_status:"500" status_codes:"4XX,5XX"`
Message string `json:"message"`
Details []string `json:"details"`
Success bool `json:"success"`
}
There are 3 status codes defined in response above.
That's why in your documentation there are 500
, 4XX
and 5XX
status codes with the response scheme above.
Error response
In order to document error response scheme, you need to define a response structure. It will be similar to the one in default response. Example:
HTTP status
You can define HTTP status returned together with the error response just inside a struct.
To do that, you need to mark your struct as an error response and add default_status
tag.
Now, you can simplify your error handler and don't return a status:
gNext will document MyResponse
scheme under 422
HTTP status code. It will also use it in response as a default status code.
You can override it, by returning gnext.Status
from handler:
func errorHandler(err error) (*MyResponse, gnext.Status) {
response := &MyResponse{Message: err.Error()}
if response.Message == "not found" {
return response, 404
}
return response, 400
}
This will return 404
HTTP status code if the error message is not found
. However, 404
code won't be documented.
To add additional status codes to documentation, you need to write comma-separated statuses to status_codes
tag of gnext.ErrorResponse
:
type MyResponse struct {
gnext.ErrorResponse `default_status:"422" status_codes:"400,404"`
Message `json:"message"`
}
Now you will see the error response with all three codes.
Warning
OpenAPI v3 scheme keeps responses in a map: status code -> response schema. This means, it is not possible to document more than one response scheme for one status code. If you register more than one response with the same status code, the random one will be exposed in documentation.