jsongorequestmux

How to minimize duplicate code in Go Mux when always trying to return same response structure?


I have tons of code similar to the following code snippet that I just try to fill my response struct, json marshal the output, set status code and return the result:

if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
            response := responses.UserResponse{
                Status:  http.StatusBadRequest,
                Message: "error",
                Data:    map[string]interface{}{"error": err.Error()},
            }
            rw.WriteHeader(http.StatusBadRequest)
            errRes, _ := json.Marshal(response)
            rw.Write(errRes)
            return
        }

I tried to create a function that receives r variable (request.http) to receive the body and also status code of the response. But noticed that I have to again check error code outside of the function and then do the same response creation flow again.

How someone expert in Go tries to minimize code duplications like these? Is this OK to have code duplication like these in first place?


Solution

  • Minimize code duplication by moving the decode call and error handling to a reusable function:

    // Decode returns true if the request body is successfully decoded
    // to the value pointed to by pv. Otherwise, decode writes an error
    // response and returns false.
    func decode(rw http.ResponseWriter, r *http.Request, pv interface{}) bool {
        err := json.NewDecoder(r.Body).Decode(pv)
        if err == nil {
            return true
        }
        rw.WriteHeader(http.StatusBadRequest)
        json.NewEncoder(rw).Encode(map[string]any{
            "status":  http.StatusBadRequest,
            "message": "error",
            "data":    map[string]any{"error": err.Error()},
        })
        return false
    }
    

    Use the function like this:

    func userHandler(rw http.ResponseWriter, r *http.Request) {
        var u UserRequest
        if !decode(rw, r, &u) {
            return
        }
    }