Jagadeesh Venkata
Jagadeesh Venkata

Reputation: 270

http override http header code in golang while there is an error in json encoding

consider this scenario!

after successful execution of a http request, what if there is an error while performing json encoding, how to override the header code

func writeResp(w http.ResponseWriter, code int, data interface{}) {
    w.Header().Set("Content-Type", "application/json")

    //Here I set the status to 201 StatusCreated
    w.WriteHeader(code) 
    s := success{Data: data}

    //what if there is an error here and want to override the status to 5xx error
    //how to handle error here, panic?, http.Error() is not an option because as we already wrote header to 201, it just prints `http: multiple response.WriteHeader calls`
    if err := json.NewEncoder(w).Encode(s); err != nil {
        w.Header().Set("Content-Type", "application/json")

        //it throws http: multiple response.WriteHeader calls here as we already wrote header above to 201
        w.WriteHeader(code)
        e := errorResponse{
            Code:        code,
            Error:       error,
            Description: msg,
        }
        if err := json.NewEncoder(w).Encode(e); err != nil {
         //same how to handle here
        }
    }
}

I have multiple options here, if we do just fatal logging the user won't know exactly what happened, even if I write string using w.Write([]byte(msg)) still the status says 201 created, how to respond with error code 5xx

any help is greatly appreciated

Upvotes: 3

Views: 4092

Answers (1)

eugenioy
eugenioy

Reputation: 12383

First of all, it does not seem very likely that you get an error when encoding.

See this question for reasons for Marshal to fail:

What input will cause golang's json.Marshal to return an error?

The other potential cause of error would be some problem with actually writing the data to the response stream, but in that case you'd not be able to write your custom error either.

Going back to your question, if you are concerned that encoding your object might fail, you can first Marshal your data (checking for error), then only write the 201 status code (and the encoded data) if marshalling succeeded.

Modifying your example a bit:

s := success{Data: data}
jsonData, err := json.Marshal(s)
if err != nil {
    // write your error to w, then return
}
w.Header().Set("Content-Type", "application/json") 
w.WriteHeader(code)
w.Write(jsonData)

Now, that last write can also throw an error.

But if that happens, it will also fail when writing your custom error, so in that case you'd better log that in the server side (or send that error to a tracker such as New Relic, etc).

Upvotes: 5

Related Questions