Skip to content

Commit 14c8c6d

Browse files
committed
Merge pull request #98 from graphql-go/context
Adds Context support.
2 parents 21b35b4 + bb0a77f commit 14c8c6d

File tree

5 files changed

+119
-11
lines changed

5 files changed

+119
-11
lines changed

definition.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"regexp"
88

99
"github.com/graphql-go/graphql/language/ast"
10+
"golang.org/x/net/context"
1011
)
1112

1213
// These are all of the possible kinds of
@@ -537,6 +538,9 @@ type ResolveParams struct {
537538
Args map[string]interface{}
538539
Info ResolveInfo
539540
Schema Schema
541+
//This can be used to provide per-request state
542+
//from the application.
543+
Context context.Context
540544
}
541545

542546
// TODO: relook at FieldResolveFn params

executor.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/graphql-go/graphql/gqlerrors"
1010
"github.com/graphql-go/graphql/language/ast"
11+
"golang.org/x/net/context"
1112
)
1213

1314
type ExecuteParams struct {
@@ -16,6 +17,10 @@ type ExecuteParams struct {
1617
AST *ast.Document
1718
OperationName string
1819
Args map[string]interface{}
20+
21+
// Context may be provided to pass application-specific per-request
22+
// information to resolve functions.
23+
Context context.Context
1924
}
2025

2126
func Execute(p ExecuteParams) (result *Result) {
@@ -29,6 +34,7 @@ func Execute(p ExecuteParams) (result *Result) {
2934
Args: p.Args,
3035
Errors: nil,
3136
Result: result,
37+
Context: p.Context,
3238
})
3339

3440
if err != nil {
@@ -62,6 +68,7 @@ type BuildExecutionCtxParams struct {
6268
Args map[string]interface{}
6369
Errors []gqlerrors.FormattedError
6470
Result *Result
71+
Context context.Context
6572
}
6673
type ExecutionContext struct {
6774
Schema Schema
@@ -70,6 +77,7 @@ type ExecutionContext struct {
7077
Operation ast.Definition
7178
VariableValues map[string]interface{}
7279
Errors []gqlerrors.FormattedError
80+
Context context.Context
7381
}
7482

7583
func buildExecutionContext(p BuildExecutionCtxParams) (*ExecutionContext, error) {
@@ -124,6 +132,7 @@ func buildExecutionContext(p BuildExecutionCtxParams) (*ExecutionContext, error)
124132
eCtx.Operation = operation
125133
eCtx.VariableValues = variableValues
126134
eCtx.Errors = p.Errors
135+
eCtx.Context = p.Context
127136
return eCtx, nil
128137
}
129138

@@ -501,9 +510,10 @@ func resolveField(eCtx *ExecutionContext, parentType *Object, source interface{}
501510
var resolveFnError error
502511

503512
result, resolveFnError = resolveFn(ResolveParams{
504-
Source: source,
505-
Args: args,
506-
Info: info,
513+
Source: source,
514+
Args: args,
515+
Info: info,
516+
Context: eCtx.Context,
507517
})
508518

509519
if resolveFnError != nil {

executor_test.go

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/graphql-go/graphql/gqlerrors"
1212
"github.com/graphql-go/graphql/language/location"
1313
"github.com/graphql-go/graphql/testutil"
14+
"golang.org/x/net/context"
1415
)
1516

1617
func TestExecutesArbitraryCode(t *testing.T) {
@@ -295,17 +296,17 @@ func TestMergesParallelFragments(t *testing.T) {
295296
}
296297
}
297298

298-
func TestThreadsContextCorrectly(t *testing.T) {
299+
func TestThreadsSourceCorrectly(t *testing.T) {
299300

300301
query := `
301302
query Example { a }
302303
`
303304

304305
data := map[string]interface{}{
305-
"contextThing": "thing",
306+
"key": "value",
306307
}
307308

308-
var resolvedContext map[string]interface{}
309+
var resolvedSource map[string]interface{}
309310

310311
schema, err := graphql.NewSchema(graphql.SchemaConfig{
311312
Query: graphql.NewObject(graphql.ObjectConfig{
@@ -314,8 +315,8 @@ func TestThreadsContextCorrectly(t *testing.T) {
314315
"a": &graphql.Field{
315316
Type: graphql.String,
316317
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
317-
resolvedContext = p.Source.(map[string]interface{})
318-
return resolvedContext, nil
318+
resolvedSource = p.Source.(map[string]interface{})
319+
return resolvedSource, nil
319320
},
320321
},
321322
},
@@ -339,9 +340,9 @@ func TestThreadsContextCorrectly(t *testing.T) {
339340
t.Fatalf("wrong result, unexpected errors: %v", result.Errors)
340341
}
341342

342-
expected := "thing"
343-
if resolvedContext["contextThing"] != expected {
344-
t.Fatalf("Expected context.contextThing to equal %v, got %v", expected, resolvedContext["contextThing"])
343+
expected := "value"
344+
if resolvedSource["key"] != expected {
345+
t.Fatalf("Expected context.key to equal %v, got %v", expected, resolvedSource["key"])
345346
}
346347
}
347348

@@ -404,6 +405,53 @@ func TestCorrectlyThreadsArguments(t *testing.T) {
404405
}
405406
}
406407

408+
func TestThreadsContextCorrectly(t *testing.T) {
409+
410+
query := `
411+
query Example { a }
412+
`
413+
414+
schema, err := graphql.NewSchema(graphql.SchemaConfig{
415+
Query: graphql.NewObject(graphql.ObjectConfig{
416+
Name: "Type",
417+
Fields: graphql.Fields{
418+
"a": &graphql.Field{
419+
Type: graphql.String,
420+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
421+
return p.Context.Value("foo"), nil
422+
},
423+
},
424+
},
425+
}),
426+
})
427+
if err != nil {
428+
t.Fatalf("Error in schema %v", err.Error())
429+
}
430+
431+
// parse query
432+
ast := testutil.TestParse(t, query)
433+
434+
// execute
435+
ep := graphql.ExecuteParams{
436+
Schema: schema,
437+
AST: ast,
438+
Context: context.WithValue(context.Background(), "foo", "bar"),
439+
}
440+
result := testutil.TestExecute(t, ep)
441+
if len(result.Errors) > 0 {
442+
t.Fatalf("wrong result, unexpected errors: %v", result.Errors)
443+
}
444+
445+
expected := &graphql.Result{
446+
Data: map[string]interface{}{
447+
"a": "bar",
448+
},
449+
}
450+
if !reflect.DeepEqual(expected, result) {
451+
t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result))
452+
}
453+
}
454+
407455
func TestNullsOutErrorSubtrees(t *testing.T) {
408456

409457
// TODO: TestNullsOutErrorSubtrees test for go-routines if implemented

graphql.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/graphql-go/graphql/gqlerrors"
55
"github.com/graphql-go/graphql/language/parser"
66
"github.com/graphql-go/graphql/language/source"
7+
"golang.org/x/net/context"
78
)
89

910
type Params struct {
@@ -12,6 +13,10 @@ type Params struct {
1213
RootObject map[string]interface{}
1314
VariableValues map[string]interface{}
1415
OperationName string
16+
17+
// Context may be provided to pass application-specific per-request
18+
// information to resolve functions.
19+
Context context.Context
1520
}
1621

1722
func Do(p Params) *Result {
@@ -39,5 +44,6 @@ func Do(p Params) *Result {
3944
AST: AST,
4045
OperationName: p.OperationName,
4146
Args: p.VariableValues,
47+
Context: p.Context,
4248
})
4349
}

graphql_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/graphql-go/graphql"
88
"github.com/graphql-go/graphql/testutil"
9+
"golang.org/x/net/context"
910
)
1011

1112
type T struct {
@@ -131,3 +132,42 @@ func TestBasicGraphQLExample(t *testing.T) {
131132
}
132133

133134
}
135+
136+
func TestThreadsContextFromParamsThrough(t *testing.T) {
137+
extractFieldFromContextFn := func(p graphql.ResolveParams) (interface{}, error) {
138+
return p.Context.Value(p.Args["key"]), nil
139+
}
140+
141+
schema, err := graphql.NewSchema(graphql.SchemaConfig{
142+
Query: graphql.NewObject(graphql.ObjectConfig{
143+
Name: "Query",
144+
Fields: graphql.Fields{
145+
"value": &graphql.Field{
146+
Type: graphql.String,
147+
Args: graphql.FieldConfigArgument{
148+
"key": &graphql.ArgumentConfig{Type: graphql.String},
149+
},
150+
Resolve: extractFieldFromContextFn,
151+
},
152+
},
153+
}),
154+
})
155+
if err != nil {
156+
t.Fatalf("wrong result, unexpected errors: %v", err.Error())
157+
}
158+
query := `{ value(key:"a") }`
159+
160+
result := graphql.Do(graphql.Params{
161+
Schema: schema,
162+
RequestString: query,
163+
Context: context.WithValue(context.TODO(), "a", "xyz"),
164+
})
165+
if len(result.Errors) > 0 {
166+
t.Fatalf("wrong result, unexpected errors: %v", result.Errors)
167+
}
168+
expected := map[string]interface{}{"value": "xyz"}
169+
if !reflect.DeepEqual(result.Data, expected) {
170+
t.Fatalf("wrong result, query: %v, graphql result diff: %v", query, testutil.Diff(expected, result))
171+
}
172+
173+
}

0 commit comments

Comments
 (0)