How to do http error handling in Go language

error-handling, go

Solution

This blog post goes into some details on how to chain multiple handler functions, which is what you should be doing. That way, you can have a validation handler, a logging handler, an authorization handler, etc etc. and just chain them together.

Essentially

func validator(next http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, req *http.Request) {
            if isRequestValid(req) {
                // a valid request is passed on to next handler
                next.ServeHTTP(w, req)
            } else {
                // otherwise, respond with an error
                http.Error(w, "Bad request - Go away!", 400)
            }
    }
    return http.HandlerFunc(fn)
}

func api1() http.Handler {
    fn := func(w http.ResponseWriter, req *http.Request) {
            // api 1 code
    }
    return http.HandlerFunc(fn)
}

func api2() http.Handler {
    fn := func(w http.ResponseWriter, req *http.Request) {
            // api 2 code
    }
    return http.HandlerFunc(fn)
}

And then chain them up in your `main` function.

func main() {
    http.Handler("/offers", validate(api1()))
    http.Handler("/getOffersList", validate(api2()))
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

Problem

I am little confused on how error handling should be done in go. I have read so many posts about it but still am not able to apply them on my structure of code. I am new to go so please help. There is a main function which handles two apis: api1 and api2 ``` func main() { http.HandleFunc("/offers", api1) http.HandleFunc("/getOffersList", api2) err := http.ListenAndServe(":8080", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } } func api1(w http.ResponseWriter, req *http.Request) { validateRequestHeader(w, req, "GET") // code here.... } func api2(w http.ResponseWriter, req *http.Request) { validateRequestHeader(w, req, "POST") //code here.... } func validateRequestHeader(w http.ResponseWriter, req *http.Request, allowedMethod string) { // allow cross domain AJAX requests w.Header().Set("Content-Type", "application/json") if origin := req.Header.Get("Origin"); origin != "" { w.Header().Set("Access-Control-Allow-Origin", origin) w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") } // Stop here if its Preflighted OPTIONS request if req.Method == "OPTIONS" { return } if req.Method != allowedMethod { response := "Only " + allowedMethod + " requests are allowed" http.Error(w, response, http.StatusMethodNotAllowed) return } } ``` In both `api1` and `api2` , function `validateRequestHeader` is getting called. If this gets true, then in the api1/api2 further code is getting executed which I do not want. How it should be handled? ``` if req.Method != allowedMethod { response := "Only " + allowedMethod + " requests are allowed" http.Error(w, response, http.StatusMethodNotAllowed) return } ```

Original source