Skip to content

Commit ef8b880

Browse files
author
Salman Ahmad
committed
Use struct fields as resolvers instead of methods (graph-gophers#28)
1 parent ce76257 commit ef8b880

File tree

10 files changed

+208
-82
lines changed

10 files changed

+208
-82
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
/internal/validation/testdata/graphql-js
22
/internal/validation/testdata/node_modules
33
/vendor
4+
.DS_Store
5+
.idea/
6+
.vscode/

config/config.go

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package config
2+
3+
type Config struct {
4+
UseResolverMethods bool
5+
}
6+
7+
func Default() *Config {
8+
return &Config{
9+
UseResolverMethods: true,
10+
}
11+
}

example/starwars/server/server.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
var schema *graphql.Schema
1313

1414
func init() {
15-
schema = graphql.MustParseSchema(starwars.Schema, &starwars.Resolver{})
15+
schema = graphql.MustParseSchema(starwars.Schema, &starwars.Resolver{}, nil)
1616
}
1717

1818
func main() {

graphql.go

+15-6
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ package graphql
22

33
import (
44
"context"
5-
"fmt"
6-
75
"encoding/json"
6+
"fmt"
87

8+
"github.com/graph-gophers/graphql-go/config"
99
"github.com/graph-gophers/graphql-go/errors"
1010
"github.com/graph-gophers/graphql-go/internal/common"
1111
"github.com/graph-gophers/graphql-go/internal/exec"
@@ -22,13 +22,21 @@ import (
2222
// ParseSchema parses a GraphQL schema and attaches the given root resolver. It returns an error if
2323
// the Go type signature of the resolvers does not match the schema. If nil is passed as the
2424
// resolver, then the schema can not be executed, but it may be inspected (e.g. with ToJSON).
25-
func ParseSchema(schemaString string, resolver interface{}, opts ...SchemaOpt) (*Schema, error) {
25+
func ParseSchema(schemaString string, resolver interface{}, conf *config.Config, opts ...SchemaOpt) (*Schema, error) {
26+
27+
// set default values in case config is null
28+
if conf == nil {
29+
conf = config.Default()
30+
}
31+
2632
s := &Schema{
27-
schema: schema.New(),
33+
schema: schema.New(conf),
34+
config: conf,
2835
maxParallelism: 10,
2936
tracer: trace.OpenTracingTracer{},
3037
logger: &log.DefaultLogger{},
3138
}
39+
3240
for _, opt := range opts {
3341
opt(s)
3442
}
@@ -49,8 +57,8 @@ func ParseSchema(schemaString string, resolver interface{}, opts ...SchemaOpt) (
4957
}
5058

5159
// MustParseSchema calls ParseSchema and panics on error.
52-
func MustParseSchema(schemaString string, resolver interface{}, opts ...SchemaOpt) *Schema {
53-
s, err := ParseSchema(schemaString, resolver, opts...)
60+
func MustParseSchema(schemaString string, resolver interface{}, conf *config.Config, opts ...SchemaOpt) *Schema {
61+
s, err := ParseSchema(schemaString, resolver, conf, opts...)
5462
if err != nil {
5563
panic(err)
5664
}
@@ -61,6 +69,7 @@ func MustParseSchema(schemaString string, resolver interface{}, opts ...SchemaOp
6169
type Schema struct {
6270
schema *schema.Schema
6371
res *resolvable.Schema
72+
config *config.Config
6473

6574
maxParallelism int
6675
tracer trace.Tracer

graphql_test.go

+14-14
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func (r *timeResolver) AddHour(args struct{ Time graphql.Time }) graphql.Time {
6161
return graphql.Time{Time: args.Time.Add(time.Hour)}
6262
}
6363

64-
var starwarsSchema = graphql.MustParseSchema(starwars.Schema, &starwars.Resolver{})
64+
var starwarsSchema = graphql.MustParseSchema(starwars.Schema, &starwars.Resolver{}, nil)
6565

6666
func TestHelloWorld(t *testing.T) {
6767
gqltesting.RunTests(t, []*gqltesting.Test{
@@ -74,7 +74,7 @@ func TestHelloWorld(t *testing.T) {
7474
type Query {
7575
hello: String!
7676
}
77-
`, &helloWorldResolver1{}),
77+
`, &helloWorldResolver1{}, nil),
7878
Query: `
7979
{
8080
hello
@@ -96,7 +96,7 @@ func TestHelloWorld(t *testing.T) {
9696
type Query {
9797
hello: String!
9898
}
99-
`, &helloWorldResolver2{}),
99+
`, &helloWorldResolver2{}, nil),
100100
Query: `
101101
{
102102
hello
@@ -122,7 +122,7 @@ func TestHelloSnake(t *testing.T) {
122122
type Query {
123123
hello_html: String!
124124
}
125-
`, &helloSnakeResolver1{}),
125+
`, &helloSnakeResolver1{}, nil),
126126
Query: `
127127
{
128128
hello_html
@@ -144,7 +144,7 @@ func TestHelloSnake(t *testing.T) {
144144
type Query {
145145
hello_html: String!
146146
}
147-
`, &helloSnakeResolver2{}),
147+
`, &helloSnakeResolver2{}, nil),
148148
Query: `
149149
{
150150
hello_html
@@ -170,7 +170,7 @@ func TestHelloSnakeArguments(t *testing.T) {
170170
type Query {
171171
say_hello(full_name: String!): String!
172172
}
173-
`, &helloSnakeResolver1{}),
173+
`, &helloSnakeResolver1{}, nil),
174174
Query: `
175175
{
176176
say_hello(full_name: "Rob Pike")
@@ -192,7 +192,7 @@ func TestHelloSnakeArguments(t *testing.T) {
192192
type Query {
193193
say_hello(full_name: String!): String!
194194
}
195-
`, &helloSnakeResolver2{}),
195+
`, &helloSnakeResolver2{}, nil),
196196
Query: `
197197
{
198198
say_hello(full_name: "Rob Pike")
@@ -606,7 +606,7 @@ func TestDeprecatedDirective(t *testing.T) {
606606
b: Int! @deprecated
607607
c: Int! @deprecated(reason: "We don't like it")
608608
}
609-
`, &testDeprecatedDirectiveResolver{}),
609+
`, &testDeprecatedDirectiveResolver{}, nil),
610610
Query: `
611611
{
612612
__type(name: "Query") {
@@ -650,7 +650,7 @@ func TestDeprecatedDirective(t *testing.T) {
650650
B @deprecated
651651
C @deprecated(reason: "We don't like it")
652652
}
653-
`, &testDeprecatedDirectiveResolver{}),
653+
`, &testDeprecatedDirectiveResolver{}, nil),
654654
Query: `
655655
{
656656
__type(name: "Test") {
@@ -1441,7 +1441,7 @@ func TestMutationOrder(t *testing.T) {
14411441
type Mutation {
14421442
changeTheNumber(newNumber: Int!): Query
14431443
}
1444-
`, &theNumberResolver{}),
1444+
`, &theNumberResolver{}, nil),
14451445
Query: `
14461446
mutation {
14471447
first: changeTheNumber(newNumber: 1) {
@@ -1485,7 +1485,7 @@ func TestTime(t *testing.T) {
14851485
}
14861486
14871487
scalar Time
1488-
`, &timeResolver{}),
1488+
`, &timeResolver{}, nil),
14891489
Query: `
14901490
query($t: Time!) {
14911491
a: addHour(time: $t)
@@ -1520,7 +1520,7 @@ func TestUnexportedMethod(t *testing.T) {
15201520
type Mutation {
15211521
changeTheNumber(newNumber: Int!): Int!
15221522
}
1523-
`, &resolverWithUnexportedMethod{})
1523+
`, &resolverWithUnexportedMethod{}, nil)
15241524
if err == nil {
15251525
t.Error("error expected")
15261526
}
@@ -1541,7 +1541,7 @@ func TestUnexportedField(t *testing.T) {
15411541
type Mutation {
15421542
changeTheNumber(newNumber: Int!): Int!
15431543
}
1544-
`, &resolverWithUnexportedField{})
1544+
`, &resolverWithUnexportedField{}, nil)
15451545
if err == nil {
15461546
t.Error("error expected")
15471547
}
@@ -1648,7 +1648,7 @@ func TestInput(t *testing.T) {
16481648
Option1
16491649
Option2
16501650
}
1651-
`, &inputResolver{})
1651+
`, &inputResolver{}, nil)
16521652
gqltesting.RunTests(t, []*gqltesting.Test{
16531653
{
16541654
Schema: coercionSchema,

internal/exec/exec.go

+21-16
Original file line numberDiff line numberDiff line change
@@ -173,22 +173,28 @@ func execFieldSelection(ctx context.Context, r *Request, f *fieldToExec, path *p
173173
return errors.Errorf("%s", err) // don't execute any more resolvers if context got cancelled
174174
}
175175

176-
var in []reflect.Value
177-
if f.field.HasContext {
178-
in = append(in, reflect.ValueOf(traceCtx))
179-
}
180-
if f.field.ArgsPacker != nil {
181-
in = append(in, f.field.PackedArgs)
182-
}
183-
callOut := f.resolver.Method(f.field.MethodIndex).Call(in)
184-
result = callOut[0]
185-
if f.field.HasError && !callOut[1].IsNil() {
186-
resolverErr := callOut[1].Interface().(error)
187-
err := errors.Errorf("%s", resolverErr)
188-
err.Path = path.toSlice()
189-
err.ResolverError = resolverErr
190-
return err
176+
if f.field.MethodIndex != -1 {
177+
var in []reflect.Value
178+
if f.field.HasContext {
179+
in = append(in, reflect.ValueOf(traceCtx))
180+
}
181+
if f.field.ArgsPacker != nil {
182+
in = append(in, f.field.PackedArgs)
183+
}
184+
185+
callOut := f.resolver.Method(f.field.MethodIndex).Call(in)
186+
result = callOut[0]
187+
if f.field.HasError && !callOut[1].IsNil() {
188+
resolverErr := callOut[1].Interface().(error)
189+
err := errors.Errorf("%s", resolverErr)
190+
err.Path = path.toSlice()
191+
err.ResolverError = resolverErr
192+
return err
193+
}
194+
} else {
195+
result = f.resolver.Field(f.field.FieldIndex)
191196
}
197+
192198
return nil
193199
}()
194200

@@ -201,7 +207,6 @@ func execFieldSelection(ctx context.Context, r *Request, f *fieldToExec, path *p
201207
f.out.WriteString("null") // TODO handle non-nil
202208
return
203209
}
204-
205210
r.execSelectionSet(traceCtx, f.sels, f.field.Type, path, result, f.out)
206211
}
207212

0 commit comments

Comments
 (0)