Skip to content
This repository has been archived by the owner on Nov 8, 2017. It is now read-only.

Commit

Permalink
Merge pull request graphql-go#80 from graphql-go/resolve-returns-error
Browse files Browse the repository at this point in the history
resolve field function can return an error
  • Loading branch information
chris-ramon committed Nov 29, 2015
2 parents 54d79ca + 1c902e8 commit 344abcc
Show file tree
Hide file tree
Showing 16 changed files with 406 additions and 209 deletions.
70 changes: 35 additions & 35 deletions abstract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) {
Fields: graphql.Fields{
"name": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if dog, ok := p.Source.(*testDog); ok {
return dog.Name
return dog.Name, nil
}
return nil
return nil, nil
},
},
"woofs": &graphql.Field{
Type: graphql.Boolean,
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if dog, ok := p.Source.(*testDog); ok {
return dog.Woofs
return dog.Woofs, nil
}
return nil
return nil, nil
},
},
},
Expand All @@ -79,20 +79,20 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) {
Fields: graphql.Fields{
"name": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if cat, ok := p.Source.(*testCat); ok {
return cat.Name
return cat.Name, nil
}
return nil
return nil, nil
},
},
"meows": &graphql.Field{
Type: graphql.Boolean,
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if cat, ok := p.Source.(*testCat); ok {
return cat.Meows
return cat.Meows, nil
}
return nil
return nil, nil
},
},
},
Expand All @@ -103,11 +103,11 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) {
Fields: graphql.Fields{
"pets": &graphql.Field{
Type: graphql.NewList(petType),
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return []interface{}{
&testDog{"Odie", true},
&testCat{"Garfield", false},
}
}, nil
},
},
},
Expand Down Expand Up @@ -202,11 +202,11 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) {
Fields: graphql.Fields{
"pets": &graphql.Field{
Type: graphql.NewList(petType),
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return []interface{}{
&testDog{"Odie", true},
&testCat{"Garfield", false},
}
}, nil
},
},
},
Expand Down Expand Up @@ -288,11 +288,11 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) {
Fields: graphql.Fields{
"name": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if human, ok := p.Source.(*testHuman); ok {
return human.Name
return human.Name, nil
}
return nil
return nil, nil
},
},
},
Expand All @@ -309,20 +309,20 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) {
Fields: graphql.Fields{
"name": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if dog, ok := p.Source.(*testDog); ok {
return dog.Name
return dog.Name, nil
}
return nil
return nil, nil
},
},
"woofs": &graphql.Field{
Type: graphql.Boolean,
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if dog, ok := p.Source.(*testDog); ok {
return dog.Woofs
return dog.Woofs, nil
}
return nil
return nil, nil
},
},
},
Expand All @@ -339,20 +339,20 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) {
Fields: graphql.Fields{
"name": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if cat, ok := p.Source.(*testCat); ok {
return cat.Name
return cat.Name, nil
}
return nil
return nil, nil
},
},
"meows": &graphql.Field{
Type: graphql.Boolean,
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if cat, ok := p.Source.(*testCat); ok {
return cat.Meows
return cat.Meows, nil
}
return nil
return nil, nil
},
},
},
Expand All @@ -363,12 +363,12 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) {
Fields: graphql.Fields{
"pets": &graphql.Field{
Type: graphql.NewList(petType),
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return []interface{}{
&testDog{"Odie", true},
&testCat{"Garfield", false},
&testHuman{"Jon"},
}
}, nil
},
},
},
Expand Down Expand Up @@ -480,12 +480,12 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) {
Fields: graphql.Fields{
"pets": &graphql.Field{
Type: graphql.NewList(petType),
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return []interface{}{
&testDog{"Odie", true},
&testCat{"Garfield", false},
&testHuman{"Jon"},
}
}, nil
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ type ResolveParams struct {
}

// TODO: relook at FieldResolveFn params
type FieldResolveFn func(p ResolveParams) interface{}
type FieldResolveFn func(p ResolveParams) (interface{}, error)

type ResolveInfo struct {
FieldName string
Expand Down
6 changes: 6 additions & 0 deletions definition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ var blogArticle = graphql.NewObject(graphql.ObjectConfig{
},
},
})

var blogQuery = graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
Expand All @@ -88,6 +89,11 @@ var blogMutation = graphql.NewObject(graphql.ObjectConfig{
Fields: graphql.Fields{
"writeArticle": &graphql.Field{
Type: blogArticle,
Args: graphql.FieldConfigArgument{
"title": &graphql.ArgumentConfig{
Type: graphql.String,
},
},
},
},
})
Expand Down
24 changes: 12 additions & 12 deletions enum_type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@ var enumTypeTestQueryType = graphql.NewObject(graphql.ObjectConfig{
Type: graphql.String,
},
},
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if fromInt, ok := p.Args["fromInt"]; ok {
return fromInt
return fromInt, nil
}
if fromString, ok := p.Args["fromString"]; ok {
return fromString
return fromString, nil
}
if fromEnum, ok := p.Args["fromEnum"]; ok {
return fromEnum
return fromEnum, nil
}
return nil
return nil, nil
},
},
"colorInt": &graphql.Field{
Expand All @@ -62,14 +62,14 @@ var enumTypeTestQueryType = graphql.NewObject(graphql.ObjectConfig{
Type: graphql.Int,
},
},
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if fromInt, ok := p.Args["fromInt"]; ok {
return fromInt
return fromInt, nil
}
if fromEnum, ok := p.Args["fromEnum"]; ok {
return fromEnum
return fromEnum, nil
}
return nil
return nil, nil
},
},
},
Expand All @@ -84,11 +84,11 @@ var enumTypeTestMutationType = graphql.NewObject(graphql.ObjectConfig{
Type: enumTypeTestColorType,
},
},
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if color, ok := p.Args["color"]; ok {
return color
return color, nil
}
return nil
return nil, nil
},
},
},
Expand Down
4 changes: 2 additions & 2 deletions examples/hello-world/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ func main() {
fields := graphql.Fields{
"hello": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) interface{} {
return "world"
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return "world", nil
},
},
}
Expand Down
6 changes: 3 additions & 3 deletions examples/http/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ var queryType = graphql.NewObject(
Type: graphql.String,
},
},
Resolve: func(p graphql.ResolveParams) interface{} {
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
idQuery, isOK := p.Args["id"].(string)
if isOK {
return data[idQuery]
return data[idQuery], nil
}
return nil
return nil, nil
},
},
},
Expand Down
24 changes: 15 additions & 9 deletions executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,12 +498,18 @@ func resolveField(eCtx *ExecutionContext, parentType *Object, source interface{}
// it is wrapped as a Error with locations. Log this error and return
// null if allowed, otherwise throw the error so the parent field can handle
// it.
result = resolveFn(ResolveParams{
var resolveFnError error

result, resolveFnError = resolveFn(ResolveParams{
Source: source,
Args: args,
Info: info,
})

if resolveFnError != nil {
panic(gqlerrors.FormatError(resolveFnError))
}

completed := completeValueCatchingError(eCtx, returnType, fieldASTs, info, result)
return completed, resultState
}
Expand Down Expand Up @@ -666,14 +672,14 @@ func completeValue(eCtx *ExecutionContext, returnType Type, fieldASTs []*ast.Fie

}

func defaultResolveFn(p ResolveParams) interface{} {
func defaultResolveFn(p ResolveParams) (interface{}, error) {
// try to resolve p.Source as a struct first
sourceVal := reflect.ValueOf(p.Source)
if sourceVal.IsValid() && sourceVal.Type().Kind() == reflect.Ptr {
sourceVal = sourceVal.Elem()
}
if !sourceVal.IsValid() {
return nil
return nil, nil
}
if sourceVal.Type().Kind() == reflect.Struct {
// find field based on struct's json tag
Expand All @@ -685,7 +691,7 @@ func defaultResolveFn(p ResolveParams) interface{} {
typeField := sourceVal.Type().Field(i)
// try matching the field name first
if typeField.Name == p.Info.FieldName {
return valueField.Interface()
return valueField.Interface(), nil
}
tag := typeField.Tag
jsonTag := tag.Get("json")
Expand All @@ -696,9 +702,9 @@ func defaultResolveFn(p ResolveParams) interface{} {
if jsonOptions[0] != p.Info.FieldName {
continue
}
return valueField.Interface()
return valueField.Interface(), nil
}
return nil
return nil, nil
}

// try p.Source as a map[string]interface
Expand All @@ -709,14 +715,14 @@ func defaultResolveFn(p ResolveParams) interface{} {
// try type casting the func to the most basic func signature
// for more complex signatures, user have to define ResolveFn
if propertyFn, ok := property.(func() interface{}); ok {
return propertyFn()
return propertyFn(), nil
}
}
return property
return property, nil
}

// last resort, return nil
return nil
return nil, nil
}

/**
Expand Down
Loading

0 comments on commit 344abcc

Please sign in to comment.