Skip to content

Commit

Permalink
google-api-go-client: Expose the raw JSON server response if non-stan…
Browse files Browse the repository at this point in the history
…dard.

When a server responds with an error, a "code:"/"message:" response is
typically used. When a custom error response is returned, it is useful
for the client to be able to parse it, so the raw JSON response is now
returned in a new field in googleapi.Error.

R=bradfitz
CC=golang-codereviews
https://codereview.appspot.com/90400043
  • Loading branch information
gmlewis committed Apr 22, 2014
1 parent daa3bf9 commit 7278d07
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 10 deletions.
30 changes: 22 additions & 8 deletions googleapi/googleapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,31 @@ type ContentTyper interface {

const Version = "0.5"

// Error contains an error response from the server.
type Error struct {
Code int `json:"code"`
// Code is the HTTP response status code and will always be populated.
Code int `json:"code"`
// Message is the server response message and is only populated when
// explicitly referenced by the JSON server response.
Message string `json:"message"`
// Body is the raw response returned by the server.
// It is often but not always JSON, depending on how the request fails.
Body string
}

func (e *Error) Error() string {
return fmt.Sprintf("googleapi: Error %d: %s", e.Code, e.Message)
if e.Message != "" {
return fmt.Sprintf("googleapi: Error %d: %v", e.Code, e.Message)
}
return fmt.Sprintf("googleapi: got HTTP response code %d with body: %v", e.Code, e.Body)
}

type errorReply struct {
Error *Error `json:"error"`
}

// CheckResponse parses the error response from the server (if any)
// and returns an Error struct if the server used the standard
// code/message JSON reponse format. If the server returned its own
// custom response, the entire raw JSON response is returned.
// CheckResponse returns an error (of type *Error) if the response
// status code is not 2xx.
func CheckResponse(res *http.Response) error {
if res.StatusCode >= 200 && res.StatusCode <= 299 {
return nil
Expand All @@ -56,11 +64,17 @@ func CheckResponse(res *http.Response) error {
jerr := new(errorReply)
err = json.Unmarshal(slurp, jerr)
if err == nil && jerr.Error != nil {
if jerr.Error.Code == 0 {
jerr.Error.Code = res.StatusCode
}
jerr.Error.Body = string(slurp)
return jerr.Error
}
}
return fmt.Errorf("googleapi: got HTTP response code %d and error reading body: %v, server response: %s",
res.StatusCode, err, slurp)
return &Error{
Code: res.StatusCode,
Body: string(slurp),
}
}

type MarshalStyle bool
Expand Down
8 changes: 6 additions & 2 deletions googleapi/googleapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,18 +120,22 @@ var checkResponseTests = []CheckResponseTest{
&http.Response{
StatusCode: http.StatusNotFound,
},
`{"error":{"code":404,"message":"Error message for StatusNotFound."}}`,
`{"error":{"message":"Error message for StatusNotFound."}}`,
&Error{
Code: http.StatusNotFound,
Message: "Error message for StatusNotFound.",
Body: `{"error":{"message":"Error message for StatusNotFound."}}`,
},
},
{
&http.Response{
StatusCode: http.StatusBadRequest,
},
`{"error":"invalid_token","error_description":"Invalid Value"}`,
fmt.Errorf(`googleapi: got HTTP response code 400 and error reading body: json: cannot unmarshal string into Go value of type googleapi.Error, server response: {"error":"invalid_token","error_description":"Invalid Value"}`),
&Error{
Code: http.StatusBadRequest,
Body: `{"error":"invalid_token","error_description":"Invalid Value"}`,
},
},
}

Expand Down

0 comments on commit 7278d07

Please sign in to comment.