13/02/2020 - GO
If you wish to return a 500 Internal Server Error
in your HTTP API without duplicating some obvious lines, you can use example below. It registers a server level middleware so all you have to do is to just call middleware.InternalServerResponse()
function.
.
├── cmd
│ └── client
│ └── main.go
├── go.mod
└── internal
├── pkg
│ └── middleware
│ ├── internalservererror.go
│ └── middleware.go
└── user
└── create.go
package main
import (
"log"
"net/http"
"internal/pkg/middleware"
"internal/user"
)
func main() {
http.HandleFunc("/users", user.Create{}.Handle)
log.Fatal(http.ListenAndServe(":8888", middleware.Server(nil, middleware.InternalServerError)))
}
package middleware
import "net/http"
// server represents a server level middleware and is used for chaining.
type server func(http.Handler) http.Handler
// Server is used for middleware chaining and dedicated to HTTP server.
func Server(handler http.Handler, middleware ...server) http.Handler {
for _, m := range middleware {
handler = m(handler)
}
return handler
}
package middleware
import "net/http"
// InternalServerError catches all `panic` calls in order to prevent HTTP server
// from going down and return a standardised 500 Internal Server Error response.
func InternalServerError(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("Standard error message."))
}
}()
handler.ServeHTTP(w, r)
})
}
// TriggerInternalServerError is called from anywhere in the application in order
// to trigger 500 Internal Server Error response.
func TriggerInternalServerError() {
panic("")
}
As you have already guessed, I am purposely calling middleware.TriggerInternalServerError()
function below.
package user
import (
"log"
"net/http"
"internal/pkg/middleware"
)
type Create struct {}
func (c Create) Handle(w http.ResponseWriter, r *http.Request) {
// This will cause 500 Internal Server error on purpose.
c.create()
// Since the function above terminates the whole process with an
// Internal Server error, this line onwards will never be executed.
w.WriteHeader(http.StatusCreated)
_, _ = w.Write([]byte("created"))
}
func (Create) create() {
// Some valid code.
// ...
// After this line, nothing after gets executed so no need for
// manual `return` or `exit`.
log.Println("Database is down.")
middleware.TriggerInternalServerError()
// Some valid code.
// ...
}
$ curl -i http://localhost:8888/users
HTTP/1.1 500 Internal Server Error
Date: Thu, 13 Feb 2020 21:32:06 GMT
Content-Length: 23
Content-Type: text/plain; charset=utf-8
Standard error message