diff --git a/abstract_test.go b/abstract_test.go index a0640cf8..37f2eb3d 100644 --- a/abstract_test.go +++ b/abstract_test.go @@ -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 }, }, }, @@ -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 }, }, }, @@ -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 }, }, }, @@ -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 }, }, }, @@ -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 }, }, }, @@ -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 }, }, }, @@ -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 }, }, }, @@ -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 }, }, }, @@ -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 }, }, }, diff --git a/definition.go b/definition.go index 657a5edc..1d226fcc 100644 --- a/definition.go +++ b/definition.go @@ -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 diff --git a/definition_test.go b/definition_test.go index 97a361fa..fb266a33 100644 --- a/definition_test.go +++ b/definition_test.go @@ -66,6 +66,7 @@ var blogArticle = graphql.NewObject(graphql.ObjectConfig{ }, }, }) + var blogQuery = graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ @@ -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, + }, + }, }, }, }) diff --git a/enum_type_test.go b/enum_type_test.go index 1db322ce..f4bcce99 100644 --- a/enum_type_test.go +++ b/enum_type_test.go @@ -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{ @@ -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 }, }, }, @@ -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 }, }, }, diff --git a/examples/hello-world/main.go b/examples/hello-world/main.go index dda06cd3..d014e942 100644 --- a/examples/hello-world/main.go +++ b/examples/hello-world/main.go @@ -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 }, }, } diff --git a/examples/http/main.go b/examples/http/main.go index 3af79bd7..26d10768 100644 --- a/examples/http/main.go +++ b/examples/http/main.go @@ -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 }, }, }, diff --git a/executor.go b/executor.go index 8f3ab359..9be274c1 100644 --- a/executor.go +++ b/executor.go @@ -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 } @@ -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 @@ -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") @@ -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 @@ -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 } /** diff --git a/executor_schema_test.go b/executor_schema_test.go index a127310a..b39c4c3a 100644 --- a/executor_schema_test.go +++ b/executor_schema_test.go @@ -106,13 +106,13 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if author, ok := p.Source.(*testAuthor); ok { width := fmt.Sprintf("%v", p.Args["width"]) height := fmt.Sprintf("%v", p.Args["height"]) - return author.Pic(width, height) + return author.Pic(width, height), nil } - return nil + return nil, nil }, }, "recentArticle": &graphql.Field{}, @@ -156,14 +156,14 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { Type: graphql.ID, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { id := p.Args["id"] - return article(id) + return article(id), nil }, }, "feed": &graphql.Field{ Type: graphql.NewList(blogArticle), - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { return []*testArticle{ article(1), article(2), @@ -175,7 +175,7 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { article(8), article(9), article(10), - } + }, nil }, }, }, diff --git a/executor_test.go b/executor_test.go index 8707b9e9..e643f31e 100644 --- a/executor_test.go +++ b/executor_test.go @@ -2,6 +2,7 @@ package graphql_test import ( "encoding/json" + "errors" "fmt" "reflect" "testing" @@ -103,18 +104,18 @@ func TestExecutesArbitraryCode(t *testing.T) { } // Schema Definitions - picResolverFn := func(p graphql.ResolveParams) interface{} { + picResolverFn := func(p graphql.ResolveParams) (interface{}, error) { // get and type assert ResolveFn for this field picResolver, ok := p.Source.(map[string]interface{})["pic"].(func(size int) string) if !ok { - return nil + return nil, nil } // get and type assert argument sizeArg, ok := p.Args["size"].(int) if !ok { - return nil + return nil, nil } - return picResolver(sizeArg) + return picResolver(sizeArg), nil } dataType := graphql.NewObject(graphql.ObjectConfig{ Name: "DataType", @@ -244,28 +245,28 @@ func TestMergesParallelFragments(t *testing.T) { Fields: graphql.Fields{ "a": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { - return "Apple" + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "Apple", nil }, }, "b": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { - return "Banana" + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "Banana", nil }, }, "c": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { - return "Cherry" + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "Cherry", nil }, }, }, }) deepTypeFieldConfig := &graphql.Field{ Type: typeObjectType, - Resolve: func(p graphql.ResolveParams) interface{} { - return p.Source + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return p.Source, nil }, } typeObjectType.AddFieldConfig("deep", deepTypeFieldConfig) @@ -312,9 +313,9 @@ func TestThreadsContextCorrectly(t *testing.T) { Fields: graphql.Fields{ "a": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { resolvedContext = p.Source.(map[string]interface{}) - return resolvedContext + return resolvedContext, nil }, }, }, @@ -368,9 +369,9 @@ func TestCorrectlyThreadsArguments(t *testing.T) { }, }, Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { resolvedArgs = p.Args - return resolvedArgs + return resolvedArgs, nil }, }, }, @@ -944,9 +945,9 @@ func TestDoesNotIncludeArgumentsThatWereNotSet(t *testing.T) { Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { args, _ := json.Marshal(p.Args) - return string(args) + return string(args), nil }, }, }, @@ -1019,8 +1020,8 @@ func TestFailsWhenAnIsTypeOfCheckIsNotMet(t *testing.T) { Fields: graphql.Fields{ "value": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { - return p.Source.(testSpecialType).Value + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return p.Source.(testSpecialType).Value, nil }, }, }, @@ -1031,8 +1032,8 @@ func TestFailsWhenAnIsTypeOfCheckIsNotMet(t *testing.T) { Fields: graphql.Fields{ "specials": &graphql.Field{ Type: graphql.NewList(specialType), - Resolve: func(p graphql.ResolveParams) interface{} { - return p.Source.(map[string]interface{})["specials"] + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return p.Source.(map[string]interface{})["specials"], nil }, }, }, @@ -1107,3 +1108,187 @@ func TestFailsToExecuteQueryContainingATypeDefinition(t *testing.T) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } } + +func TestQuery_ExecutionAddsErrorsFromFieldResolveFn(t *testing.T) { + qError := errors.New("queryError") + q := graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "a": &graphql.Field{ + Type: graphql.String, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return nil, qError + }, + }, + "b": &graphql.Field{ + Type: graphql.String, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "ok", nil + }, + }, + }, + }) + blogSchema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: q, + }) + if err != nil { + t.Fatalf("unexpected error, got: %v", err) + } + query := "{ a }" + result := graphql.Do(graphql.Params{ + Schema: blogSchema, + RequestString: query, + }) + if len(result.Errors) == 0 { + t.Fatal("wrong result, expected errors, got no errors") + } + if result.Errors[0].Error() != qError.Error() { + t.Fatalf("wrong result, unexpected error, got: %v, expected: %v", result.Errors[0], qError) + } +} + +func TestQuery_ExecutionDoesNotAddErrorsFromFieldResolveFn(t *testing.T) { + qError := errors.New("queryError") + q := graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "a": &graphql.Field{ + Type: graphql.String, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return nil, qError + }, + }, + "b": &graphql.Field{ + Type: graphql.String, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "ok", nil + }, + }, + }, + }) + blogSchema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: q, + }) + if err != nil { + t.Fatalf("unexpected error, got: %v", err) + } + query := "{ b }" + result := graphql.Do(graphql.Params{ + Schema: blogSchema, + RequestString: query, + }) + if len(result.Errors) != 0 { + t.Fatalf("wrong result, unexpected errors: %+v", result.Errors) + } +} + +func TestMutation_ExecutionAddsErrorsFromFieldResolveFn(t *testing.T) { + mError := errors.New("mutationError") + q := graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "a": &graphql.Field{ + Type: graphql.String, + }, + }, + }) + m := graphql.NewObject(graphql.ObjectConfig{ + Name: "Mutation", + Fields: graphql.Fields{ + "foo": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "f": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return nil, mError + }, + }, + "bar": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "b": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "ok", nil + }, + }, + }, + }) + schema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: q, + Mutation: m, + }) + if err != nil { + t.Fatalf("unexpected error, got: %v", err) + } + query := "mutation _ { newFoo: foo(f:\"title\") }" + result := graphql.Do(graphql.Params{ + Schema: schema, + RequestString: query, + }) + if len(result.Errors) == 0 { + t.Fatal("wrong result, expected errors, got no errors") + } + if result.Errors[0].Error() != mError.Error() { + t.Fatalf("wrong result, unexpected error, got: %v, expected: %v", result.Errors[0], mError) + } +} + +func TestMutation_ExecutionDoesNotAddErrorsFromFieldResolveFn(t *testing.T) { + mError := errors.New("mutationError") + q := graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "a": &graphql.Field{ + Type: graphql.String, + }, + }, + }) + m := graphql.NewObject(graphql.ObjectConfig{ + Name: "Mutation", + Fields: graphql.Fields{ + "foo": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "f": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return nil, mError + }, + }, + "bar": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "b": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "ok", nil + }, + }, + }, + }) + schema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: q, + Mutation: m, + }) + if err != nil { + t.Fatalf("unexpected error, got: %v", err) + } + query := "mutation _ { newBar: bar(b:\"title\") }" + result := graphql.Do(graphql.Params{ + Schema: schema, + RequestString: query, + }) + if len(result.Errors) != 0 { + t.Fatalf("wrong result, unexpected errors: %+v", result.Errors) + } +} diff --git a/graphql_test.go b/graphql_test.go index fc0473d5..07c3e508 100644 --- a/graphql_test.go +++ b/graphql_test.go @@ -94,8 +94,8 @@ func testGraphql(test T, p graphql.Params, t *testing.T) { func TestBasicGraphQLExample(t *testing.T) { // taken from `graphql-js` README - helloFieldResolved := func(p graphql.ResolveParams) interface{} { - return "world" + helloFieldResolved := func(p graphql.ResolveParams) (interface{}, error) { + return "world", nil } schema, err := graphql.NewSchema(graphql.SchemaConfig{ diff --git a/introspection.go b/introspection.go index dd91e5d2..0323a23e 100644 --- a/introspection.go +++ b/introspection.go @@ -86,26 +86,26 @@ func init() { Fields: Fields{ "kind": &Field{ Type: NewNonNull(__TypeKind), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { switch p.Source.(type) { case *Scalar: - return TypeKindScalar + return TypeKindScalar, nil case *Object: - return TypeKindObject + return TypeKindObject, nil case *Interface: - return TypeKindInterface + return TypeKindInterface, nil case *Union: - return TypeKindUnion + return TypeKindUnion, nil case *Enum: - return TypeKindEnum + return TypeKindEnum, nil case *InputObject: - return TypeKindInputObject + return TypeKindInputObject, nil case *List: - return TypeKindList + return TypeKindList, nil case *NonNull: - return TypeKindNonNull + return TypeKindNonNull, nil } - panic(fmt.Sprintf("Unknown kind of type: %v", p.Source)) + return nil, fmt.Errorf("Unknown kind of type: %v", p.Source) }, }, "name": &Field{ @@ -137,22 +137,22 @@ func init() { }, "defaultValue": &Field{ Type: String, - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if inputVal, ok := p.Source.(*Argument); ok { if inputVal.DefaultValue == nil { - return nil + return nil, nil } astVal := astFromValue(inputVal.DefaultValue, inputVal) - return printer.Print(astVal) + return printer.Print(astVal), nil } if inputVal, ok := p.Source.(*InputObjectField); ok { if inputVal.DefaultValue == nil { - return nil + return nil, nil } astVal := astFromValue(inputVal.DefaultValue, inputVal) - return printer.Print(astVal) + return printer.Print(astVal), nil } - return nil + return nil, nil }, }, }, @@ -169,11 +169,11 @@ func init() { }, "args": &Field{ Type: NewNonNull(NewList(NewNonNull(__InputValue))), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if field, ok := p.Source.(*FieldDefinition); ok { - return field.Args + return field.Args, nil } - return []interface{}{} + return []interface{}{}, nil }, }, "type": &Field{ @@ -181,11 +181,11 @@ func init() { }, "isDeprecated": &Field{ Type: NewNonNull(Boolean), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if field, ok := p.Source.(*FieldDefinition); ok { - return (field.DeprecationReason != "") + return (field.DeprecationReason != ""), nil } - return false + return false, nil }, }, "deprecationReason": &Field{ @@ -232,38 +232,38 @@ mutation operations.`, Type: NewNonNull(NewList( NewNonNull(__Type), )), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { results := []Type{} for _, ttype := range schema.TypeMap() { results = append(results, ttype) } - return results + return results, nil } - return []Type{} + return []Type{}, nil }, }, "queryType": &Field{ Description: "The type that query operations will be rooted at.", Type: NewNonNull(__Type), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { - return schema.QueryType() + return schema.QueryType(), nil } - return nil + return nil, nil }, }, "mutationType": &Field{ Description: `If this server supports mutation, the type that ` + `mutation operations will be rooted at.`, Type: __Type, - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { if schema.MutationType() != nil { - return schema.MutationType() + return schema.MutationType(), nil } } - return nil + return nil, nil }, }, "directives": &Field{ @@ -271,11 +271,11 @@ mutation operations.`, Type: NewNonNull(NewList( NewNonNull(__Directive), )), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { - return schema.Directives() + return schema.Directives(), nil } - return nil + return nil, nil }, }, }, @@ -292,11 +292,11 @@ mutation operations.`, }, "isDeprecated": &Field{ Type: NewNonNull(Boolean), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if field, ok := p.Source.(*EnumValueDefinition); ok { - return (field.DeprecationReason != "") + return (field.DeprecationReason != ""), nil } - return false + return false, nil }, }, "deprecationReason": &Field{ @@ -315,12 +315,12 @@ mutation operations.`, DefaultValue: false, }, }, - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { includeDeprecated, _ := p.Args["includeDeprecated"].(bool) switch ttype := p.Source.(type) { case *Object: if ttype == nil { - return nil + return nil, nil } fields := []*FieldDefinition{} for _, field := range ttype.Fields() { @@ -329,10 +329,10 @@ mutation operations.`, } fields = append(fields, field) } - return fields + return fields, nil case *Interface: if ttype == nil { - return nil + return nil, nil } fields := []*FieldDefinition{} for _, field := range ttype.Fields() { @@ -341,31 +341,31 @@ mutation operations.`, } fields = append(fields, field) } - return fields + return fields, nil } - return nil + return nil, nil }, }) __Type.AddFieldConfig("interfaces", &Field{ Type: NewList(NewNonNull(__Type)), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { switch ttype := p.Source.(type) { case *Object: - return ttype.Interfaces() + return ttype.Interfaces(), nil } - return nil + return nil, nil }, }) __Type.AddFieldConfig("possibleTypes", &Field{ Type: NewList(NewNonNull(__Type)), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { switch ttype := p.Source.(type) { case *Interface: - return ttype.PossibleTypes() + return ttype.PossibleTypes(), nil case *Union: - return ttype.PossibleTypes() + return ttype.PossibleTypes(), nil } - return nil + return nil, nil }, }) __Type.AddFieldConfig("enumValues", &Field{ @@ -376,12 +376,12 @@ mutation operations.`, DefaultValue: false, }, }, - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { includeDeprecated, _ := p.Args["includeDeprecated"].(bool) switch ttype := p.Source.(type) { case *Enum: if includeDeprecated { - return ttype.Values() + return ttype.Values(), nil } values := []*EnumValueDefinition{} for _, value := range ttype.Values() { @@ -390,23 +390,23 @@ mutation operations.`, } values = append(values, value) } - return values + return values, nil } - return nil + return nil, nil }, }) __Type.AddFieldConfig("inputFields", &Field{ Type: NewList(NewNonNull(__InputValue)), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { switch ttype := p.Source.(type) { case *InputObject: fields := []*InputObjectField{} for _, field := range ttype.Fields() { fields = append(fields, field) } - return fields + return fields, nil } - return nil + return nil, nil }, }) __Type.AddFieldConfig("ofType", &Field{ @@ -423,8 +423,8 @@ mutation operations.`, Type: NewNonNull(__Schema), Description: "Access the current type schema of this server.", Args: []*Argument{}, - Resolve: func(p ResolveParams) interface{} { - return p.Info.Schema + Resolve: func(p ResolveParams) (interface{}, error) { + return p.Info.Schema, nil }, } TypeMetaFieldDef = &FieldDefinition{ @@ -437,12 +437,12 @@ mutation operations.`, Type: NewNonNull(String), }, }, - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { name, ok := p.Args["name"].(string) if !ok { - return nil + return nil, nil } - return p.Info.Schema.Type(name) + return p.Info.Schema.Type(name), nil }, } @@ -451,8 +451,8 @@ mutation operations.`, Type: NewNonNull(String), Description: "The name of the current Object type at runtime.", Args: []*Argument{}, - Resolve: func(p ResolveParams) interface{} { - return p.Info.ParentType.Name() + Resolve: func(p ResolveParams) (interface{}, error) { + return p.Info.ParentType.Name(), nil }, } diff --git a/introspection_test.go b/introspection_test.go index 1d314e93..b0e785e6 100644 --- a/introspection_test.go +++ b/introspection_test.go @@ -768,8 +768,8 @@ func TestIntrospection_ExecutesAnInputObject(t *testing.T) { Type: testInputObject, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { - return p.Args["complex"] + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return p.Args["complex"], nil }, }, }, diff --git a/lists_test.go b/lists_test.go index 5dad96c3..4bc47cd7 100644 --- a/lists_test.go +++ b/lists_test.go @@ -25,8 +25,8 @@ func checkList(t *testing.T, testType graphql.Type, testData interface{}, expect }) dataType.AddFieldConfig("nest", &graphql.Field{ Type: dataType, - Resolve: func(p graphql.ResolveParams) interface{} { - return data + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return data, nil }, }) diff --git a/mutations_test.go b/mutations_test.go index eb076dcb..0a52d136 100644 --- a/mutations_test.go +++ b/mutations_test.go @@ -66,11 +66,11 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) - return obj.ImmediatelyChangeTheNumber(newNumber) + return obj.ImmediatelyChangeTheNumber(newNumber), nil }, }, "promiseToChangeTheNumber": &graphql.Field{ @@ -80,11 +80,11 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) - return obj.PromiseToChangeTheNumber(newNumber) + return obj.PromiseToChangeTheNumber(newNumber), nil }, }, "failToChangeTheNumber": &graphql.Field{ @@ -94,11 +94,11 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) - return obj.FailToChangeTheNumber(newNumber) + return obj.FailToChangeTheNumber(newNumber), nil }, }, "promiseAndFailToChangeTheNumber": &graphql.Field{ @@ -108,11 +108,11 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) - return obj.PromiseAndFailToChangeTheNumber(newNumber) + return obj.PromiseAndFailToChangeTheNumber(newNumber), nil }, }, }, diff --git a/testutil/testutil.go b/testutil/testutil.go index 11c0fc06..972ee240 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -156,51 +156,51 @@ func init() { "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the human.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { - return human.Id + return human.Id, nil } - return nil + return nil, nil }, }, "name": &graphql.Field{ Type: graphql.String, Description: "The name of the human.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { - return human.Name + return human.Name, nil } - return nil + return nil, nil }, }, "friends": &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the human, or an empty list if they have none.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { - return human.Friends + return human.Friends, nil } - return []interface{}{} + return []interface{}{}, nil }, }, "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { - return human.AppearsIn + return human.AppearsIn, nil } - return nil + return nil, nil }, }, "homePlanet": &graphql.Field{ Type: graphql.String, Description: "The home planet of the human, or null if unknown.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { - return human.HomePlanet + return human.HomePlanet, nil } - return nil + return nil, nil }, }, }, @@ -215,27 +215,27 @@ func init() { "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the droid.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { - return droid.Id + return droid.Id, nil } - return nil + return nil, nil }, }, "name": &graphql.Field{ Type: graphql.String, Description: "The name of the droid.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { - return droid.Name + return droid.Name, nil } - return nil + return nil, nil }, }, "friends": &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the droid, or an empty list if they have none.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { friends := []map[string]interface{}{} for _, friend := range droid.Friends { @@ -244,29 +244,29 @@ func init() { "id": friend.Id, }) } - return droid.Friends + return droid.Friends, nil } - return []interface{}{} + return []interface{}{}, nil }, }, "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { - return droid.AppearsIn + return droid.AppearsIn, nil } - return nil + return nil, nil }, }, "primaryFunction": &graphql.Field{ Type: graphql.String, Description: "The primary function of the droid.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { - return droid.PrimaryFunction + return droid.PrimaryFunction, nil } - return nil + return nil, nil }, }, }, @@ -287,8 +287,8 @@ func init() { Type: episodeEnum, }, }, - Resolve: func(p graphql.ResolveParams) (r interface{}) { - return GetHero(p.Args["episode"]) + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return GetHero(p.Args["episode"]), nil }, }, "human": &graphql.Field{ @@ -299,8 +299,8 @@ func init() { Type: graphql.NewNonNull(graphql.String), }, }, - Resolve: func(p graphql.ResolveParams) (r interface{}) { - return GetHuman(p.Args["id"].(int)) + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return GetHuman(p.Args["id"].(int)), nil }, }, "droid": &graphql.Field{ @@ -311,8 +311,8 @@ func init() { Type: graphql.NewNonNull(graphql.String), }, }, - Resolve: func(p graphql.ResolveParams) (r interface{}) { - return GetDroid(p.Args["id"].(int)) + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return GetDroid(p.Args["id"].(int)), nil }, }, }, diff --git a/variables_test.go b/variables_test.go index cc9126b0..b8e118f2 100644 --- a/variables_test.go +++ b/variables_test.go @@ -53,16 +53,16 @@ var testInputObject *graphql.InputObject = graphql.NewInputObject(graphql.InputO }, }) -func inputResolved(p graphql.ResolveParams) interface{} { +func inputResolved(p graphql.ResolveParams) (interface{}, error) { input, ok := p.Args["input"] if !ok { - return nil + return nil, nil } b, err := json.Marshal(input) if err != nil { - return nil + return nil, nil } - return string(b) + return string(b), nil } var testType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{