From 1aa881b8b0267fb8eb4702c6c63172f791a45772 Mon Sep 17 00:00:00 2001 From: "stephen.raymond" Date: Mon, 24 Jun 2019 08:49:53 -0600 Subject: [PATCH 1/4] grErrs type as error --- graphql.go | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/graphql.go b/graphql.go index 05c29b7..b0e52fb 100644 --- a/graphql.go +++ b/graphql.go @@ -35,11 +35,11 @@ import ( "context" "encoding/json" "fmt" + "github.com/pkg/errors" "io" "mime/multipart" "net/http" - - "github.com/pkg/errors" + "strings" ) // Client is a client for interacting with a GraphQL API. @@ -143,11 +143,8 @@ func (c *Client) runWithJSON(ctx context.Context, req *Request, resp interface{} } return errors.Wrap(err, "decoding response") } - if len(gr.Errors) > 0 { - // return first error - return gr.Errors[0] - } - return nil + + return gr.Errors } func (c *Client) runWithPostFields(ctx context.Context, req *Request, resp interface{}) error { @@ -214,11 +211,8 @@ func (c *Client) runWithPostFields(ctx context.Context, req *Request, resp inter } return errors.Wrap(err, "decoding response") } - if len(gr.Errors) > 0 { - // return first error - return gr.Errors[0] - } - return nil + + return gr.Errors } // WithHTTPClient specifies the underlying http.Client to use when @@ -249,6 +243,23 @@ func ImmediatelyCloseReqBody() ClientOption { // modify the behaviour of the Client. type ClientOption func(*Client) +type graphErrs []graphErr + +func (e graphErrs) Error() string { + if len(e) == 1 { + return fmt.Sprintf("1 error occurred:\n\t* %s\n\n", e[0]) + } + + points := make([]string, len(e)) + for i, err := range e { + points[i] = fmt.Sprintf("* %s", err) + } + + return fmt.Sprintf( + "%d errors occurred:\n\t%s\n\n", + len(e), strings.Join(points, "\n\t")) +} + type graphErr struct { Message string } @@ -259,7 +270,7 @@ func (e graphErr) Error() string { type graphResponse struct { Data interface{} - Errors []graphErr + Errors graphErrs } // Request is a GraphQL request. From 3e374ee1ff2d471f1939b804fb51cad013dc6b43 Mon Sep 17 00:00:00 2001 From: "stephen.raymond" Date: Mon, 24 Jun 2019 09:25:16 -0600 Subject: [PATCH 2/4] http client interface --- graphql.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/graphql.go b/graphql.go index b0e52fb..2a66f01 100644 --- a/graphql.go +++ b/graphql.go @@ -45,7 +45,7 @@ import ( // Client is a client for interacting with a GraphQL API. type Client struct { endpoint string - httpClient *http.Client + httpClient httpDoer useMultipartForm bool // closeReq will close the request body immediately allowing for reuse of client @@ -218,7 +218,7 @@ func (c *Client) runWithPostFields(ctx context.Context, req *Request, resp inter // WithHTTPClient specifies the underlying http.Client to use when // making requests. // NewClient(endpoint, WithHTTPClient(specificHTTPClient)) -func WithHTTPClient(httpclient *http.Client) ClientOption { +func WithHTTPClient(httpclient httpDoer) ClientOption { return func(client *Client) { client.httpClient = httpclient } @@ -261,7 +261,7 @@ func (e graphErrs) Error() string { } type graphErr struct { - Message string + Message string `json:"message"` } func (e graphErr) Error() string { @@ -269,8 +269,8 @@ func (e graphErr) Error() string { } type graphResponse struct { - Data interface{} - Errors graphErrs + Data interface{} `json:"data"` + Errors graphErrs `json:"errors"` } // Request is a GraphQL request. @@ -333,3 +333,7 @@ type File struct { Name string R io.Reader } + +type httpDoer interface { + Do(req *http.Request) (*http.Response, error) +} From bd1081f45286ca4a58197a7531a13ebef3d5f7d3 Mon Sep 17 00:00:00 2001 From: "stephen.raymond" Date: Mon, 24 Jun 2019 09:47:38 -0600 Subject: [PATCH 3/4] return nil if no errors --- graphql.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/graphql.go b/graphql.go index 2a66f01..a8ea9c0 100644 --- a/graphql.go +++ b/graphql.go @@ -144,7 +144,10 @@ func (c *Client) runWithJSON(ctx context.Context, req *Request, resp interface{} return errors.Wrap(err, "decoding response") } - return gr.Errors + if len(gr.Errors) > 0 { + return gr.Errors + } + return nil } func (c *Client) runWithPostFields(ctx context.Context, req *Request, resp interface{}) error { @@ -212,7 +215,10 @@ func (c *Client) runWithPostFields(ctx context.Context, req *Request, resp inter return errors.Wrap(err, "decoding response") } - return gr.Errors + if len(gr.Errors) > 0 { + return gr.Errors + } + return nil } // WithHTTPClient specifies the underlying http.Client to use when From 27048eb9113e740f5bc964facc49c344c298f4b6 Mon Sep 17 00:00:00 2001 From: "stephen.raymond" Date: Sun, 14 Jul 2019 11:58:40 -0600 Subject: [PATCH 4/4] fix tests --- graphql_json_test.go | 4 +++- graphql_multipart_test.go | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/graphql_json_test.go b/graphql_json_test.go index a973d2d..17800d5 100644 --- a/graphql_json_test.go +++ b/graphql_json_test.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "net/http" "net/http/httptest" + "strings" "testing" "time" @@ -92,7 +93,8 @@ func TestDoJSONBadRequestErr(t *testing.T) { var responseData map[string]interface{} err := client.Run(ctx, &Request{q: "query {}"}, &responseData) is.Equal(calls, 1) // calls - is.Equal(err.Error(), "graphql: miscellaneous message as to why the the request was bad") + is.Equal(len(err.(graphErrs)), 1) + is.True(strings.Contains(err.Error(), "graphql: miscellaneous message as to why the the request was bad")) } func TestQueryJSON(t *testing.T) { diff --git a/graphql_multipart_test.go b/graphql_multipart_test.go index b52da2c..ce31860 100644 --- a/graphql_multipart_test.go +++ b/graphql_multipart_test.go @@ -114,7 +114,7 @@ func TestDoErr(t *testing.T) { var responseData map[string]interface{} err := client.Run(ctx, &Request{q: "query {}"}, &responseData) is.True(err != nil) - is.Equal(err.Error(), "graphql: Something went wrong") + is.True(strings.Contains(err.Error(), "graphql: Something went wrong")) } func TestDoServerErr(t *testing.T) { @@ -164,7 +164,7 @@ func TestDoBadRequestErr(t *testing.T) { defer cancel() var responseData map[string]interface{} err := client.Run(ctx, &Request{q: "query {}"}, &responseData) - is.Equal(err.Error(), "graphql: miscellaneous message as to why the the request was bad") + is.True(strings.Contains(err.Error(), "graphql: miscellaneous message as to why the the request was bad")) } func TestDoNoResponse(t *testing.T) {