Repository: jensneuse/graphql-go-tools
Pull request #74 (2019-05-10 21:44:39)

Pass variables along with outgoing request to backend graphql server
In response to #73 


Patch:
diff --git a/pkg/middleware/invoker.go b/pkg/middleware/invoker.go
index e571db2f..da64ac71 100644
--- a/pkg/middleware/invoker.go
+++ b/pkg/middleware/invoker.go
@@ -8,6 +8,12 @@ import (
 	"io"
 )
 
+type GraphQLRequest struct {
+	OperationName string `json:"operationName,omitempty"`
+	Query         string `json:"query"`
+	Variables     map[string]interface{} `json:"variables,omitempty"`
+}
+
 type Invoker struct {
 	middleWares []GraphqlMiddleware
 	parse       *parser.Parser
diff --git a/pkg/proxy/http/proxy.go b/pkg/proxy/http/proxy.go
index 9d542b55..28156c20 100644
--- a/pkg/proxy/http/proxy.go
+++ b/pkg/proxy/http/proxy.go
@@ -25,11 +25,6 @@ type ProxyRequest struct {
 	Proxy *Proxy
 }
 
-type GraphqlJsonRequest struct {
-	OperationName string `json:"operationName,omitempty"`
-	Query         string `json:"query"`
-}
-
 func (pr *ProxyRequest) AcceptRequest(buff *bytes.Buffer) error {
 
 	idx, invoker := pr.Proxy.InvokerPool.Get()
@@ -40,15 +35,7 @@ func (pr *ProxyRequest) AcceptRequest(buff *bytes.Buffer) error {
 		return err
 	}
 
-	var graphqlJsonRequest GraphqlJsonRequest
-	err = json.NewDecoder(pr.Body).Decode(&graphqlJsonRequest)
-	if err != nil {
-		return err
-	}
-
-	query := []byte(graphqlJsonRequest.Query)
-
-	err = invoker.InvokeMiddleWares(pr.Context, query) // TODO: fix nil
+	err = invoker.InvokeMiddleWares(pr.Context, []byte(pr.GraphQLRequest.Query)) // TODO: fix nil
 	if err != nil {
 		return err
 	}
@@ -62,9 +49,10 @@ func (pr *ProxyRequest) AcceptRequest(buff *bytes.Buffer) error {
 }
 
 func (pr *ProxyRequest) DispatchRequest(buff *bytes.Buffer) (io.ReadCloser, error) {
-
-	req := GraphqlJsonRequest{
+	req := middleware.GraphQLRequest{
 		Query: buff.String(),
+		OperationName: pr.GraphQLRequest.OperationName,
+		Variables: pr.GraphQLRequest.Variables,
 	}
 
 	out := bytes.Buffer{}
@@ -117,7 +105,14 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	pr.Body = r.Body
 	pr.Context = p.SetContextValues(r.Context(), r.Header, config.AddHeadersToContext)
 
-	err := pr.AcceptRequest(buff)
+	err := json.NewDecoder(pr.Body).Decode(&pr.GraphQLRequest)
+	if err != nil {
+		p.BufferPool.Put(buff)
+		p.HandleError(err, w)
+		return
+	}
+
+	err = pr.AcceptRequest(buff)
 	if err != nil {
 		p.BufferPool.Put(buff)
 		p.HandleError(err, w)
diff --git a/pkg/proxy/proxy.go b/pkg/proxy/proxy.go
index b6eac46f..a234fcad 100644
--- a/pkg/proxy/proxy.go
+++ b/pkg/proxy/proxy.go
@@ -21,6 +21,7 @@ type Request struct {
 	RequestURL url.URL
 	Body       io.Reader
 	Context    context.Context
+	GraphQLRequest middleware.GraphQLRequest
 }
 
 type RequestInterface interface {


Test patch:
diff --git a/pkg/proxy/http/proxy_test.go b/pkg/proxy/http/proxy_test.go
index ceeac6b6..8ef77df6 100644
--- a/pkg/proxy/http/proxy_test.go
+++ b/pkg/proxy/http/proxy_test.go
@@ -21,8 +21,8 @@ func TestProxyHandler(t *testing.T) {
 		if err != nil {
 			t.Fatal(err)
 		}
-		if string(body) != assetOutput {
-			t.Fatalf("Expected:\n%s\ngot\n%s", assetOutput, body)
+		if strings.TrimSpace(string(body)) != assetOutput {
+			t.Fatalf("Expected:\n%s\ngot\n%s", assetOutput, string(body))
 		}
 	}))
 	defer es.Close()
@@ -90,6 +90,41 @@ func TestProxyHandlerError(t *testing.T) {
 	})
 }
 
+func TestProxyHandlerVariables(t *testing.T) {
+	endpointServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		body, err := ioutil.ReadAll(r.Body)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if strings.TrimSpace(string(body)) != variableAssetOutput {
+			t.Fatalf("Expected:\n%s\ngot\n%s", variableAssetOutput, body)
+		}
+	}))
+	defer endpointServer.Close()
+
+	schema := []byte(assetSchema)
+	backendURL, err := url.Parse(endpointServer.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	requestConfigProvider := proxy.NewStaticRequestConfigProvider(proxy.RequestConfig{
+		Schema:     &schema,
+		BackendURL: *backendURL,
+	})
+
+	proxyHandler := NewDefaultProxy(requestConfigProvider, &hackmiddleware.AssetUrlMiddleware{})
+	testServer := httptest.NewServer(proxyHandler)
+	defer testServer.Close()
+
+	t.Run("Test proxy handler", func(t *testing.T) {
+		_, err := http.Post(testServer.URL, "application/graphql", strings.NewReader(variableAssetInput))
+		if err != nil {
+			t.Error(err)
+		}
+	})
+}
+
 func BenchmarkProxyHandler(b *testing.B) {
 
 	//go printMemUsage()
@@ -173,7 +208,8 @@ type Asset implements Node {
     url: String!
 }`
 
-const assetInput = `{"query":"query testQueryWithoutHandle {assets(first: 1) { id fileName url(transformation: {image: {resize: {width: 100, height: 100}}})}}"}`
+const assetInput = `{"query":"query testQueryWithoutHandle {assets(first:1) { id fileName url(transformation: {image: {resize: {width: 100, height: 100}}})}}"}`
+const assetOutput = `{"query":"query testQueryWithoutHandle {assets(first:1) {id fileName handle}}"}`
 
-const assetOutput = `{"query":"query testQueryWithoutHandle {assets(first:1) {id fileName handle}}"}
-`
+const variableAssetInput = `{"query":"query testQueryWithoutHandle {assets(first: 1) { id fileName url(transformation: {image: {resize: {width: 100, height: 100}}})}}","variables":{"id":1}}`
+const variableAssetOutput = `{"query":"query testQueryWithoutHandle {assets(first:1) {id fileName handle}}","variables":{"id":1}}`