Repository: jensneuse/graphql-go-tools
Pull request #125 (2019-12-02 07:41:17)

fix variable extraction from GraphQL Request
Variable extraction into the context object led to unwanted quoted strings. This PR fixes the problem.


Patch:
diff --git a/pkg/execution/datasource_graphql.go b/pkg/execution/datasource_graphql.go
index 2cb0163e..cc399876 100644
--- a/pkg/execution/datasource_graphql.go
+++ b/pkg/execution/datasource_graphql.go
@@ -328,9 +328,17 @@ func (g *GraphQLDataSource) Resolve(ctx Context, args ResolvedArgs, out io.Write
 		}
 	}
 
+	variablesJson,err := json.Marshal(variables)
+	if err != nil {
+		g.log.Error("GraphQLDataSource.json.Marshal(variables)",
+			zap.Error(err),
+		)
+		return CloseConnectionIfNotStream
+	}
+
 	gqlRequest := GraphqlRequest{
 		OperationName: "o",
-		Variables:     variables,
+		Variables:     variablesJson,
 		Query:         string(queryArg),
 	}
 
diff --git a/pkg/execution/handler.go b/pkg/execution/handler.go
index 36cb5d81..37bcde5e 100644
--- a/pkg/execution/handler.go
+++ b/pkg/execution/handler.go
@@ -4,6 +4,7 @@ package execution
 import (
 	"bytes"
 	"encoding/json"
+	"github.com/buger/jsonparser"
 	"github.com/cespare/xxhash"
 	"github.com/gobuffalo/packr"
 	"github.com/jensneuse/graphql-go-tools/pkg/ast"
@@ -66,7 +67,7 @@ func (h *Handler) RenderGraphQLDefinitions(out io.Writer) error {
 
 type GraphqlRequest struct {
 	OperationName string                     `json:"operation_name"`
-	Variables     map[string]json.RawMessage `json:"variables"`
+	Variables     json.RawMessage `json:"variables"`
 	Query         string                     `json:"query"`
 }
 
@@ -84,10 +85,7 @@ func (h *Handler) Handle(data []byte) (executor *Executor, node RootNode, ctx Co
 		return
 	}
 
-	variables := make(Variables, len(graphqlRequest.Variables))
-	for key := range graphqlRequest.Variables {
-		variables[xxhash.Sum64String(key)] = graphqlRequest.Variables[key]
-	}
+	variables := h.VariablesFromRequest(graphqlRequest)
 
 	planner := NewPlanner(h.resolverDefinitions(&report))
 	if report.HasErrors() {
@@ -131,6 +129,15 @@ func (h *Handler) Handle(data []byte) (executor *Executor, node RootNode, ctx Co
 	return executor, plan, ctx, err
 }
 
+func (h *Handler) VariablesFromRequest(request GraphqlRequest) Variables {
+	variables := make(Variables, 4)
+	_ = jsonparser.ObjectEach(request.Variables, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
+		variables[xxhash.Sum64(key)] = value
+		return nil
+	})
+	return variables
+}
+
 func (h *Handler) resolverDefinitions(report *operationreport.Report) ResolverDefinitions {
 
 	baseDataSourcePlanner := BaseDataSourcePlanner{


Test patch:
diff --git a/pkg/execution/execution_test.go b/pkg/execution/execution_test.go
index c5eab653..f33cc3e5 100644
--- a/pkg/execution/execution_test.go
+++ b/pkg/execution/execution_test.go
@@ -1199,6 +1199,37 @@ func TestExecutor_ResolveArgs(t *testing.T) {
 	}
 }
 
+func TestExecutor_ResolveArgsString(t *testing.T) {
+	e := NewExecutor()
+	e.context = Context{
+		Context: context.Background(),
+		Variables: map[uint64][]byte{
+			xxhash.Sum64String("id"): []byte("foo123"),
+		},
+	}
+
+	args := []Argument{
+		&StaticVariableArgument{
+			Name:  []byte("url"),
+			Value: []byte("/apis/{{ .arguments.id }}"),
+		},
+		&ContextVariableArgument{
+			Name:         []byte(".arguments.id"),
+			VariableName: []byte("id"),
+		},
+	}
+
+	resolved := e.ResolveArgs(args, nil)
+	if len(resolved) != 1 {
+		t.Fatalf("want 1, got: %d\n", len(resolved))
+		return
+	}
+	want := []byte("/apis/foo123")
+	if !bytes.Equal(resolved.ByKey([]byte("url")), want) {
+		t.Fatalf("want key 'body' with value: '%s'\ndump: %s", string(want), resolved.Dump())
+	}
+}
+
 func TestExecutor_ResolveArgsComplexPayload(t *testing.T) {
 	e := NewExecutor()
 	e.context = Context{
diff --git a/pkg/execution/handler_test.go b/pkg/execution/handler_test.go
index ed067707..6599e137 100644
--- a/pkg/execution/handler_test.go
+++ b/pkg/execution/handler_test.go
@@ -2,6 +2,7 @@ package execution
 
 import (
 	"bytes"
+	"github.com/cespare/xxhash"
 	"github.com/jensneuse/diffview"
 	"github.com/sebdah/goldie"
 	"go.uber.org/zap"
@@ -42,3 +43,24 @@ func TestHandler_RenderGraphQLDefinitions(t *testing.T) {
 		diffview.NewGoland().DiffViewBytes("render_graphql_definitions", want, got)
 	}
 }
+
+func TestHandler_VariablesFromRequest(t *testing.T) {
+	handler, err := NewHandler(nil, zap.NewNop())
+	if err != nil {
+		t.Fatal(err)
+	}
+	request := GraphqlRequest{
+		Variables: []byte(`{"foo":"bar"}`),
+	}
+	variables := handler.VariablesFromRequest(request)
+
+	for key,value := range map[string]string{
+		"foo": "bar",
+	}{
+		got := string(variables[xxhash.Sum64String(key)])
+		want := value
+		if got != want{
+			t.Errorf("want {{ %s }}, got: {{ %s }}'",want,got)
+		}
+	}
+}
\ No newline at end of file