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.


Structure


.
├── cmd
│   └── client
│   └── main.go
├── go.mod
└── internal
├── pkg
│   └── middleware
│   ├── internalservererror.go
│   └── middleware.go
└── user
└── create.go

Files


main.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)))
}

middleware.go


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
}

internalservererror.go


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("")
}

create.go


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.
// ...
}

Test


$ 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