HTTP error handling
With BunRouter, you can and should use middlewares to handle all errors from a single place. BunRouter does not provide a built-in error handler, but you can easily create your own.
For example, let's create an error handler for a JSON API that generates responses like this whenever there is an error:
{
"code": "login_required",
"message": "You must log in before continuing"
}
Let's start by defining a struct that will carry some information about an error:
type HTTPError struct {
statusCode int
Code string `json:"code"`
Message string `json:"message"`
}
func (e HTTPError) Error() string {
return e.Message
}
Next, we need some logic to convert an error
into a HTTPError
:
func NewHTTPError(err error) HTTPError {
switch err {
case io.EOF:
return HTTPError{
statusCode: http.StatusBadRequest,
Code: "eof",
Message: "EOF reading HTTP request body",
}
case sql.ErrNoRows:
return HTTPError{
statusCode: http.StatusNotFound,
Code: "not_found",
Message: "Page Not Found",
}
}
return HTTPError{
statusCode: http.StatusInternalServerError,
Code: "internal",
Message: "Internal server error",
}
}
Lastly, we need a middleware that pulls everything together:
func errorHandler(next bunrouter.HandlerFunc) bunrouter.HandlerFunc {
return func(w http.ResponseWriter, req bunrouter.Request) error {
// Call the next handler on the chain to get the error.
err := next(w, req)
switch err := err.(type) {
case nil:
// no error
case HTTPError: // already a HTTPError
w.WriteHeader(err.statusCode)
_ = bunrouter.JSON(w, err)
default:
httpErr := NewHTTPError(err)
w.WriteHeader(httpErr.statusCode)
_ = bunrouter.JSON(w, httpErr)
}
return err // return the err in case there other middlewares
}
}
It is a good idea to isolate the API by creating a separate routing group and installing error handler only for that group:
api := router.NewGroup("/api", bunrouter.Use(errorHandler))
api.GET("/", indexHandler)
You can find the source code on GitHub.