Reputation: 43
How can I call multiple error return functions from a Handlefunc?
I have found something similar to what I need in this link: Golang: terminating or aborting an HTTP request.
So, in some cases, I need to return error response with HTTP error code, like below (code taken from link above):
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// examine incoming params
if !ok {
http.Error(w, `Invalid input params!`, http.StatusBadRequest)
return
}
// Do normal API serving
})
However, in some cases I need to return a JSON response to the web client:
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// examine incoming params
if !ok {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
str := `{"Result":"","Error":"No valide Var"}`
fmt.Fprint(w, str)
return
}
// Do normal API serving
})
Question is: I want to place the error handling part in a seperate error function and passing what type of error I want to present as a function parameter/method. However I don't know, how to do it semantically.
So, in the gist:
if isJsonError {
//call HTTP function to serve JSON error
}
if isHTTPError {
//call HTTP function to serve an HTTP error
}
How can I do that semantically? Sorry in advance, if I'm not being clear. Thank you!
P.S.: I've also read the following blogpost : http://blog.golang.org/error-handling-and-go
There is a section there called "Simplifying repetitive error handling" - and it's cool but I need to simplify multiple repetitive error handling and I can't figure out how to.
Upvotes: 3
Views: 10340
Reputation: 24250
The custom handler approach (as per that blog post)—with a func(w http.ResponseWriter, r *http.Request) error
signature is certainly a good way to go. You could return &HTTPError{err, code}
or a &JSONError{err, code}
and have ServeHTTP
inspect and render appropriately. e.g.
type Handler struct {
h func(http.ResponseWriter, *http.Request) error
}
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Execute the handler function
err := h.h(w, r)
if err != nil {
switch e := err.(type) {
case *HTMLError:
// Render a HTML response, calling e.Err and e.Code
case *JSONError:
// Render a JSON response
default:
// Handle all other 'generic' errors you don't inspect
}
}
}
type HTMLError struct {
Err error
Code int
}
func (e *HTMLError) Error() string {
return e.Err.Error()
}
type JSONError struct {
Err error
Code int
}
func (e *JSONError) Error() string {
return e.Err.Error()
}
func SomeHandler(w http.ResponseWriter, r *http.Request) error {
// examine incoming params
if !ok {
// Your returns are also enforced here - avoiding subtle bugs
return &HTTPError{errors.New("No good!"), http.StatusBadRequest}
}
}
Small plug: I wrote a blog post about ways to centralise error handling with handlers that is similar to the example above.
Upvotes: 6
Reputation: 99215
Something like this:
func badReq(w http.ResponseWriter, isJson bool, err string) {
if !isJson {
http.Error(w, err, http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, `{"result":"","error":%q}`, err)
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if !ok {
badReq(w, true, "no valid var")
return
}
})
Upvotes: 16