From e4a3a37e6d42afa87afee2edeeced52300b63893 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Mon, 24 Sep 2018 00:19:50 -0400 Subject: [PATCH] Include response body in non-200 OK error text. When a GraphQL server returns a non-200 OK status code, it may be very helpful to for caller to know what the response body was. So, when such an error occurs, fetch the response body and include it in the returned error text. Fixes #29. Updates #24. --- graphql.go | 6 +++++- graphql_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/graphql.go b/graphql.go index f2c5b54..e0248fd 100644 --- a/graphql.go +++ b/graphql.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "io/ioutil" "net/http" "github.com/shurcooL/go/ctxhttp" @@ -70,7 +71,8 @@ func (c *Client) do(ctx context.Context, op operationType, v interface{}, variab } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return fmt.Errorf("unexpected status: %v", resp.Status) + body, _ := ioutil.ReadAll(resp.Body) + return fmt.Errorf("non-200 OK status code: %v body: %q", resp.Status, body) } var out struct { Data *json.RawMessage @@ -79,11 +81,13 @@ func (c *Client) do(ctx context.Context, op operationType, v interface{}, variab } err = json.NewDecoder(resp.Body).Decode(&out) if err != nil { + // TODO: Consider including response body in returned error, if deemed helpful. return err } if out.Data != nil { err := jsonutil.UnmarshalGraphQL(*out.Data, v) if err != nil { + // TODO: Consider including response body in returned error, if deemed helpful. return err } } diff --git a/graphql_test.go b/graphql_test.go index 4262c3f..e09dcc9 100644 --- a/graphql_test.go +++ b/graphql_test.go @@ -101,6 +101,30 @@ func TestClient_Query_noDataWithErrorResponse(t *testing.T) { } } +func TestClient_Query_errorStatusCode(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/graphql", func(w http.ResponseWriter, req *http.Request) { + http.Error(w, "important message", http.StatusInternalServerError) + }) + client := graphql.NewClient("/graphql", &http.Client{Transport: localRoundTripper{handler: mux}}) + + var q struct { + User struct { + Name graphql.String + } + } + err := client.Query(context.Background(), &q, nil) + if err == nil { + t.Fatal("got error: nil, want: non-nil") + } + if got, want := err.Error(), `non-200 OK status code: 500 Internal Server Error body: "important message\n"`; got != want { + t.Errorf("got error: %v, want: %v", got, want) + } + if q.User.Name != "" { + t.Errorf("got non-empty q.User.Name: %v", q.User.Name) + } +} + // Test that an empty (but non-nil) variables map is // handled no differently than a nil variables map. func TestClient_Query_emptyVariables(t *testing.T) {