From 62e14e7714b389770c3a23d181ef89b0fd37ad2a Mon Sep 17 00:00:00 2001 From: Iheanyi Ekechukwu Date: Wed, 9 Oct 2019 15:50:45 -0400 Subject: [PATCH 1/4] Add variadic RequestOptions. --- graphql.go | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/graphql.go b/graphql.go index 8520956..baf2253 100644 --- a/graphql.go +++ b/graphql.go @@ -30,22 +30,33 @@ func NewClient(url string, httpClient *http.Client) *Client { } } +// RequestOption is a variadic option for modifying an underlying HTTP request +// for GraphQL. +type RequestOption func(req *http.Request) + +// WithRequestHeader sets an explicit HTTP header for usage +func WithRequestHeader(key, value string) RequestOption { + return func(req *http.Request) { + req.Header.Set(key, value) + } +} + // Query executes a single GraphQL query request, // with a query derived from q, populating the response into it. // q should be a pointer to struct that corresponds to the GraphQL schema. -func (c *Client) Query(ctx context.Context, q interface{}, variables map[string]interface{}) error { - return c.do(ctx, queryOperation, q, variables) +func (c *Client) Query(ctx context.Context, q interface{}, variables map[string]interface{}, opts ...RequestOption) error { + return c.do(ctx, queryOperation, q, variables, opts...) } // Mutate executes a single GraphQL mutation request, // with a mutation derived from m, populating the response into it. // m should be a pointer to struct that corresponds to the GraphQL schema. -func (c *Client) Mutate(ctx context.Context, m interface{}, variables map[string]interface{}) error { - return c.do(ctx, mutationOperation, m, variables) +func (c *Client) Mutate(ctx context.Context, m interface{}, variables map[string]interface{}, opts ...RequestOption) error { + return c.do(ctx, mutationOperation, m, variables, opts...) } // do executes a single GraphQL operation. -func (c *Client) do(ctx context.Context, op operationType, v interface{}, variables map[string]interface{}) error { +func (c *Client) do(ctx context.Context, op operationType, v interface{}, variables map[string]interface{}, opts ...RequestOption) error { var query string switch op { case queryOperation: @@ -65,7 +76,17 @@ func (c *Client) do(ctx context.Context, op operationType, v interface{}, variab if err != nil { return err } - resp, err := ctxhttp.Post(ctx, c.httpClient, c.url, "application/json", &buf) + req, err := http.NewRequest(http.MethodPost, c.url, &buf) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + + for _, opt := range opts { + opt(req) + } + + resp, err := ctxhttp.Do(ctx, c.httpClient, req) if err != nil { return err } From e52f203d170a6436386017e3a552f562fc73f5bc Mon Sep 17 00:00:00 2001 From: Iheanyi Ekechukwu Date: Wed, 9 Oct 2019 16:45:02 -0400 Subject: [PATCH 2/4] Switch to using go vet . --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 93b1fcd..12607ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,5 +12,5 @@ install: script: - go get -t -v ./... - diff -u <(echo -n) <(gofmt -d -s .) - - go tool vet . + - go vet . - go test -v -race ./... From 8c221a6732e8270a8c31fbf7feda981aec5938e0 Mon Sep 17 00:00:00 2001 From: Iheanyi Ekechukwu Date: Sat, 12 Oct 2019 15:08:53 -0400 Subject: [PATCH 3/4] Add tests for WithRequestHeader. --- graphql_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/graphql_test.go b/graphql_test.go index e09dcc9..c04a5f0 100644 --- a/graphql_test.go +++ b/graphql_test.go @@ -153,6 +153,30 @@ func TestClient_Query_emptyVariables(t *testing.T) { } } +func TestClient_Query_requestOptions(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/graphql", func(w http.ResponseWriter, req *http.Request) { + header := req.Header.Get("Custom-Request-Header") + if got, want := header, "test-custom-header"; got != want { + t.Errorf("got header: %v, want %v", got, want) + } + + w.Header().Set("Content-Type", "application/json") + mustWrite(w, `{"data": {"user": {"name": "Gopher"}}}`) + }) + client := graphql.NewClient("/graphql", &http.Client{Transport: localRoundTripper{handler: mux}}) + + var q struct { + User struct { + Name string + } + } + err := client.Query(context.Background(), &q, map[string]interface{}{}, graphql.WithRequestHeader("Custom-Request-Header", "test-custom-header")) + if err != nil { + t.Fatal(err) + } +} + // localRoundTripper is an http.RoundTripper that executes HTTP transactions // by using handler directly, instead of going over an HTTP connection. type localRoundTripper struct { From ea55ef29e09549a8732b42661154d83d3ebefc55 Mon Sep 17 00:00:00 2001 From: Iheanyi Ekechukwu Date: Sat, 12 Oct 2019 17:04:06 -0400 Subject: [PATCH 4/4] Return error from functional option. --- graphql.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/graphql.go b/graphql.go index baf2253..bcdb520 100644 --- a/graphql.go +++ b/graphql.go @@ -32,12 +32,13 @@ func NewClient(url string, httpClient *http.Client) *Client { // RequestOption is a variadic option for modifying an underlying HTTP request // for GraphQL. -type RequestOption func(req *http.Request) +type RequestOption func(req *http.Request) error // WithRequestHeader sets an explicit HTTP header for usage func WithRequestHeader(key, value string) RequestOption { - return func(req *http.Request) { + return func(req *http.Request) error { req.Header.Set(key, value) + return nil } } @@ -83,7 +84,10 @@ func (c *Client) do(ctx context.Context, op operationType, v interface{}, variab req.Header.Set("Content-Type", "application/json") for _, opt := range opts { - opt(req) + err := opt(req) + if err != nil { + return err + } } resp, err := ctxhttp.Do(ctx, c.httpClient, req)