Jagrati
Jagrati

Reputation: 12222

Error Handling in Go is returning empty error object in http response

I am create API in go. Everything is working fine only that when there is an error I want to show it to the user. I am using go's errors package.

Below is the sample code:

type ErrorResponse struct {
        Status string `json:"status"`
        Error  error  `json:"error"`
    }
err := errors.New("Total Price cannot be a negative value")
errRes := ErrorResponse{"ERROR", err}
response, errr := json.Marshal(errRes)
if errr != nil {
    log.Fatal(err)
    return
}
io.WriteString(w, string(response))

The response I am getting is:

{
  "status": "ERROR",
  "error": {} //why is this empty
}

error key should have string Total Price cannot be a negative value. I don't understand the problem.

Upvotes: 0

Views: 4355

Answers (1)

jussius
jussius

Reputation: 3274

Error types can't marshal themselves to JSON. There's a few ways to work around this. If you don't want to change your ErrorResponse struct then pretty much the only way is to define a custom MarshalJSON method for your struct where you tell the marshaler to use the string returned by the Error's .Error() method.

func (resp ErrorResponse) MarshalJSON() ([]byte, error) {
    return json.Marshal(&struct {
        Status string `json:"status"`
        Error  string `json:"error"`
    }{
        Status: resp.Status,
        Error:  resp.Error.Error(),
    })
}

https://play.golang.org/p/EgVj_4Cc3W

If you want to marshal errors into JSON elsewhere also. Then you could use a custom error type and define marshaling for that, e.g:

type MyError struct {
    Error error
}

func (err MyError) MarshalJSON() ([]byte, error) {
    return json.Marshal(err.Error.Error())
}

https://play.golang.org/p/sjOHj9X0tO

Simplest (and probably the best) way is to just use a string in your response struct. It makes sense because the actual value you send in the http response is obviously a string, not an error interface.

type ErrorResponse struct {
        Status string `json:"status"`
        Error  string  `json:"error"`
    }
err := errors.New("Total Price cannot be a negative value")
errRes := ErrorResponse{"ERROR", err.Error()}
response, errr := json.Marshal(errRes)
if errr != nil {
    log.Fatal(err)
    // you should write something to responseWriter w here before returning
    http.Error(w, "Internal server error", http.StatusInternalServerError)
    return
}
io.WriteString(w, string(response))

Note that in case the marshaling fails, you should still write some kind of response before returning.

Upvotes: 7

Related Questions