func TestTypeSystem_DefinitionExample_DefinesAMutationScheme(t *testing.T) { blogSchema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: blogQuery, Mutation: blogMutation, }) if err != nil { t.Fatalf("unexpected error, got: %v", err) } if blogSchema.GetMutationType() != blogMutation { t.Fatalf("expected blogSchema.GetMutationType() == blogMutation") } writeMutation, _ := blogMutation.GetFields()["writeArticle"] if writeMutation == nil { t.Fatalf("writeMutation is nil") } writeMutationType := writeMutation.Type if writeMutationType != blogArticle { t.Fatalf("writeMutationType expected to equal blogArticle, got: %v", writeMutationType) } if writeMutationType.GetName() != "Article" { t.Fatalf("writeMutationType.Name expected to equal `Article`, got: %v", writeMutationType.GetName()) } if writeMutation.Name != "writeArticle" { t.Fatalf("writeMutation.Name expected to equal `writeArticle`, got: %v", writeMutation.Name) } }
func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichRedefinesABuiltInType(t *testing.T) { fakeString := graphql.NewScalar(graphql.ScalarConfig{ Name: "String", Serialize: func(value interface{}) interface{} { return nil }, }) queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "normal": &graphql.FieldConfig{ Type: graphql.String, }, "fake": &graphql.FieldConfig{ Type: fakeString, }, }, }) _, err := graphql.NewSchema(graphql.SchemaConfig{ Query: queryType, }) expectedError := `Schema must contain unique named types but contains multiple types named "String".` if err == nil || err.Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, err) } }
func TestTypeSystem_SchemaMustHaveObjectRootTypes_RejectsASchemaWithoutAQueryType(t *testing.T) { _, err := graphql.NewSchema(graphql.SchemaConfig{}) expectedError := "Schema query must be Object Type but got: nil." if err == nil || err.Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, err) } }
func schemaWithInputFieldOfType(ttype graphql.Type) (graphql.Schema, error) { badInputObject := graphql.NewInputObject(graphql.InputObjectConfig{ Name: "BadInputObject", Fields: graphql.InputObjectConfigFieldMap{ "badField": &graphql.InputObjectFieldConfig{ Type: ttype, }, }, }) return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "badArg": &graphql.ArgumentConfig{ Type: badInputObject, }, }, }, }, }), }) }
func TestIntrospection_IdentifiesDeprecatedFields(t *testing.T) { testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.FieldConfigMap{ "nonDeprecated": &graphql.FieldConfig{ Type: graphql.String, }, "deprecated": &graphql.FieldConfig{ Type: graphql.String, DeprecationReason: "Removed in 1.0", }, }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: testType, }) if err != nil { t.Fatalf("Error creating Schema: %v", err.Error()) } query := ` { __type(name: "TestType") { name fields(includeDeprecated: true) { name isDeprecated, deprecationReason } } } ` expected := &graphql.Result{ Data: map[string]interface{}{ "__type": map[string]interface{}{ "name": "TestType", "fields": []interface{}{ map[string]interface{}{ "name": "nonDeprecated", "isDeprecated": false, "deprecationReason": nil, }, map[string]interface{}{ "name": "deprecated", "isDeprecated": true, "deprecationReason": "Removed in 1.0", }, }, }, }, } result := g(t, graphql.Params{ Schema: schema, RequestString: query, }) if !testutil.ContainSubset(result.Data.(map[string]interface{}), expected.Data.(map[string]interface{})) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } }
func TestTypeSystem_SchemaMustHaveObjectRootTypes_AcceptsASchemaWhoseQueryTypeIsAnObjectType(t *testing.T) { _, err := graphql.NewSchema(graphql.SchemaConfig{ Query: someObjectType, }) if err != nil { t.Fatalf("unexpected error: %v", err) } }
func TestCorrectlyThreadsArguments(t *testing.T) { query := ` query Example { b(numArg: 123, stringArg: "foo") } ` var resolvedArgs map[string]interface{} schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.FieldConfigMap{ "b": &graphql.FieldConfig{ Args: graphql.FieldConfigArgument{ "numArg": &graphql.ArgumentConfig{ Type: graphql.Int, }, "stringArg": &graphql.ArgumentConfig{ Type: graphql.String, }, }, Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { resolvedArgs = p.Args return resolvedArgs }, }, }, }), }) if err != nil { t.Fatalf("Error in schema %v", err.Error()) } // parse query ast := testutil.TestParse(t, query) // execute ep := graphql.ExecuteParams{ Schema: schema, AST: ast, } result := testutil.TestExecute(t, ep) if len(result.Errors) > 0 { t.Fatalf("wrong result, unexpected errors: %v", result.Errors) } expectedNum := 123 expectedString := "foo" if resolvedArgs["numArg"] != expectedNum { t.Fatalf("Expected args.numArg to equal `%v`, got `%v`", expectedNum, resolvedArgs["numArg"]) } if resolvedArgs["stringArg"] != expectedString { t.Fatalf("Expected args.stringArg to equal `%v`, got `%v`", expectedNum, resolvedArgs["stringArg"]) } }
func TestAvoidsRecursion(t *testing.T) { doc := ` query Q { a ...Frag ...Frag } fragment Frag on Type { a, ...Frag } ` data := map[string]interface{}{ "a": "b", } expected := &graphql.Result{ Data: map[string]interface{}{ "a": "b", }, } schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.FieldConfigMap{ "a": &graphql.FieldConfig{ Type: graphql.String, }, }, }), }) if err != nil { t.Fatalf("Error in schema %v", err.Error()) } // parse query ast := testutil.TestParse(t, doc) // execute ep := graphql.ExecuteParams{ Schema: schema, AST: ast, Root: data, OperationName: "Q", } result := testutil.TestExecute(t, ep) if len(result.Errors) > 0 { t.Fatalf("wrong result, unexpected errors: %v", result.Errors) } if !reflect.DeepEqual(expected, result) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } }
func schemaWithFieldType(ttype graphql.Output) (graphql.Schema, error) { return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: ttype, }, }, }), }) }
func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichHaveSameNamedObjectsImplementingAnInterface(t *testing.T) { anotherInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: graphql.String, }, }, }) _ = graphql.NewObject(graphql.ObjectConfig{ Name: "BadObject", Interfaces: []*graphql.Interface{ anotherInterface, }, Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: graphql.String, }, }, }) _ = graphql.NewObject(graphql.ObjectConfig{ Name: "BadObject", Interfaces: []*graphql.Interface{ anotherInterface, }, Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: graphql.String, }, }, }) queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "iface": &graphql.FieldConfig{ Type: anotherInterface, }, }, }) _, err := graphql.NewSchema(graphql.SchemaConfig{ Query: queryType, }) expectedError := `Schema must contain unique named types but contains multiple types named "BadObject".` if err == nil || err.Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, err) } }
func TestThreadsContextCorrectly(t *testing.T) { query := ` query Example { a } ` data := map[string]interface{}{ "contextThing": "thing", } var resolvedContext map[string]interface{} schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.FieldConfigMap{ "a": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { resolvedContext = p.Source.(map[string]interface{}) return resolvedContext }, }, }, }), }) if err != nil { t.Fatalf("Error in schema %v", err.Error()) } // parse query ast := testutil.TestParse(t, query) // execute ep := graphql.ExecuteParams{ Schema: schema, Root: data, AST: ast, } result := testutil.TestExecute(t, ep) if len(result.Errors) > 0 { t.Fatalf("wrong result, unexpected errors: %v", result.Errors) } expected := "thing" if resolvedContext["contextThing"] != expected { t.Fatalf("Expected context.contextThing to equal %v, got %v", expected, resolvedContext["contextThing"]) } }
func TestDoesNotIncludeIllegalFieldsInOutput(t *testing.T) { doc := `mutation M { thisIsIllegalDontIncludeMe }` expected := &graphql.Result{ Data: map[string]interface{}{}, } schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Q", Fields: graphql.FieldConfigMap{ "a": &graphql.FieldConfig{ Type: graphql.String, }, }, }), Mutation: graphql.NewObject(graphql.ObjectConfig{ Name: "M", Fields: graphql.FieldConfigMap{ "c": &graphql.FieldConfig{ Type: graphql.String, }, }, }), }) if err != nil { t.Fatalf("Error in schema %v", err.Error()) } // parse query ast := testutil.TestParse(t, doc) // execute ep := graphql.ExecuteParams{ Schema: schema, AST: ast, } result := testutil.TestExecute(t, ep) if len(result.Errors) != 0 { t.Fatalf("wrong result, expected len(%v) errors, got len(%v)", len(expected.Errors), len(result.Errors)) } if !reflect.DeepEqual(expected, result) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } }
func TestThrowsIfNoOperationIsProvidedWithMultipleOperations(t *testing.T) { doc := `query Example { a } query OtherExample { a }` data := map[string]interface{}{ "a": "b", } expectedErrors := []gqlerrors.FormattedError{ gqlerrors.FormattedError{ Message: "Must provide operation name if query contains multiple operations.", Locations: []location.SourceLocation{}, }, } schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.FieldConfigMap{ "a": &graphql.FieldConfig{ Type: graphql.String, }, }, }), }) if err != nil { t.Fatalf("Error in schema %v", err.Error()) } // parse query ast := testutil.TestParse(t, doc) // execute ep := graphql.ExecuteParams{ Schema: schema, AST: ast, Root: data, } result := testutil.TestExecute(t, ep) if len(result.Errors) != 1 { t.Fatalf("wrong result, expected len(1) unexpected len: %v", len(result.Errors)) } if result.Data != nil { t.Fatalf("wrong result, expected nil result.Data, got %v", result.Data) } if !reflect.DeepEqual(expectedErrors, result.Errors) { t.Fatalf("unexpected result, Diff: %v", testutil.Diff(expectedErrors, result.Errors)) } }
func TestFailsToExecuteQueryContainingATypeDefinition(t *testing.T) { query := ` { foo } type Query { foo: String } ` expected := &graphql.Result{ Data: nil, Errors: []gqlerrors.FormattedError{ gqlerrors.FormattedError{ Message: "GraphQL cannot execute a request containing a ObjectDefinition", Locations: []location.SourceLocation{}, }, }, } schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "foo": &graphql.FieldConfig{ Type: graphql.String, }, }, }), }) if err != nil { t.Fatalf("Error in schema %v", err.Error()) } // parse query ast := testutil.TestParse(t, query) // execute ep := graphql.ExecuteParams{ Schema: schema, AST: ast, } result := testutil.TestExecute(t, ep) if len(result.Errors) != 1 { t.Fatalf("wrong result, unexpected errors: %v", result.Errors) } if !reflect.DeepEqual(expected, result) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } }
func schemaWithInputObject(ttype graphql.Input) (graphql.Schema, error) { return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "args": &graphql.ArgumentConfig{ Type: ttype, }, }, }, }, }), }) }
func TestTypeSystem_SchemaMustHaveObjectRootTypes_AcceptsASchemaWhoseQueryAndMutationTypesAreObjectType(t *testing.T) { mutationObject := graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", Fields: graphql.FieldConfigMap{ "edit": &graphql.FieldConfig{ Type: graphql.String, }, }, }) _, err := graphql.NewSchema(graphql.SchemaConfig{ Query: someObjectType, Mutation: mutationObject, }) if err != nil { t.Fatalf("unexpected error: %v", err) } }
func checkList(t *testing.T, testType graphql.Type, testData interface{}, expected *graphql.Result) { data := map[string]interface{}{ "test": testData, } dataType := graphql.NewObject(graphql.ObjectConfig{ Name: "DataType", Fields: graphql.FieldConfigMap{ "test": &graphql.FieldConfig{ Type: testType, }, }, }) dataType.AddFieldConfig("nest", &graphql.FieldConfig{ Type: dataType, Resolve: func(p graphql.GQLFRParams) interface{} { return data }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: dataType, }) if err != nil { t.Fatalf("Error in schema %v", err.Error()) } // parse query ast := testutil.TestParse(t, `{ nest { test } }`) // execute ep := graphql.ExecuteParams{ Schema: schema, AST: ast, Root: data, } result := testutil.TestExecute(t, ep) if len(expected.Errors) != len(result.Errors) { t.Fatalf("wrong result, Diff: %v", testutil.Diff(expected.Errors, result.Errors)) } if !reflect.DeepEqual(expected, result) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } }
func TestIntrospection_FailsAsExpectedOnThe__TypeRootFieldWithoutAnArg(t *testing.T) { testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.FieldConfigMap{ "testField": &graphql.FieldConfig{ Type: graphql.String, }, }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: testType, }) if err != nil { t.Fatalf("Error creating Schema: %v", err.Error()) } query := ` { __type { name } } ` expected := &graphql.Result{ Errors: []gqlerrors.FormattedError{ gqlerrors.FormattedError{ Message: `Field "__type" argument "name" of type "String!" ` + `is required but not provided.`, Locations: []location.SourceLocation{ location.SourceLocation{Line: 3, Column: 9}, }, }, }, } result := g(t, graphql.Params{ Schema: schema, RequestString: query, }) t.Skipf("Pending `validator` implementation") if !reflect.DeepEqual(expected, result) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } }
func TestBasicGraphQLExample(t *testing.T) { // taken from `graphql-js` README helloFieldResolved := func(p graphql.GQLFRParams) interface{} { return "world" } schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "RootQueryType", Fields: graphql.FieldConfigMap{ "hello": &graphql.FieldConfig{ Description: "Returns `world`", Type: graphql.String, Resolve: helloFieldResolved, }, }, }), }) if err != nil { t.Fatalf("wrong result, unexpected errors: %v", err.Error()) } query := "{ hello }" var expected interface{} expected = map[string]interface{}{ "hello": "world", } resultChannel := make(chan *graphql.Result) go graphql.Graphql(graphql.Params{ Schema: schema, RequestString: query, }, resultChannel) result := <-resultChannel if len(result.Errors) > 0 { t.Fatalf("wrong result, unexpected errors: %v", result.Errors) } if !reflect.DeepEqual(result.Data, expected) { t.Fatalf("wrong result, query: %v, graphql result diff: %v", query, testutil.Diff(expected, result)) } }
func TestTypeSystem_DefinitionExample_IncludesInterfacesThunkSubtypesInTheTypeMap(t *testing.T) { someInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "SomeInterface", Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: graphql.Int, }, }, }) someSubType := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeSubtype", Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: graphql.Int, }, }, Interfaces: (graphql.InterfacesThunk)(func() []*graphql.Interface { return []*graphql.Interface{someInterface} }), IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { return true }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "iface": &graphql.FieldConfig{ Type: someInterface, }, }, }), }) if err != nil { t.Fatalf("unexpected error, got: %v", err) } if schema.GetType("SomeSubtype") != someSubType { t.Fatalf(`schema.GetType("SomeSubtype") expected to equal someSubType, got: %v`, schema.GetType("SomeSubtype")) } }
func schemaWithUnionOfType(ttype *graphql.Object) (graphql.Schema, error) { badObjectType := graphql.NewUnion(graphql.UnionConfig{ Name: "BadUnion", ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, Types: []*graphql.Object{ttype}, }) return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: badObjectType, }, }, }), }) }
func TestTypeSystem_DefinitionExample_IncludesNestedInputObjectsInTheMap(t *testing.T) { nestedInputObject := graphql.NewInputObject(graphql.InputObjectConfig{ Name: "NestedInputObject", Fields: graphql.InputObjectConfigFieldMap{ "value": &graphql.InputObjectFieldConfig{ Type: graphql.String, }, }, }) someInputObject := graphql.NewInputObject(graphql.InputObjectConfig{ Name: "SomeInputObject", Fields: graphql.InputObjectConfigFieldMap{ "nested": &graphql.InputObjectFieldConfig{ Type: nestedInputObject, }, }, }) someMutation := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeMutation", Fields: graphql.FieldConfigMap{ "mutateSomething": &graphql.FieldConfig{ Type: blogArticle, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ Type: someInputObject, }, }, }, }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: blogQuery, Mutation: someMutation, }) if err != nil { t.Fatalf("unexpected error, got: %v", err) } if schema.GetType("NestedInputObject") != nestedInputObject { t.Fatalf(`schema.GetType("NestedInputObject") expected to equal nestedInputObject, got: %v`, schema.GetType("NestedInputObject")) } }
func schemaWithObjectFieldOfType(fieldType graphql.Input) (graphql.Schema, error) { badObjectType := graphql.NewObject(graphql.ObjectConfig{ Name: "BadObject", Fields: graphql.FieldConfigMap{ "badField": &graphql.FieldConfig{ Type: fieldType, }, }, }) return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: badObjectType, }, }, }), }) }
func schemaWithInterfaceFieldOfType(ttype graphql.Type) (graphql.Schema, error) { badInterfaceType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "BadInterface", Fields: graphql.FieldConfigMap{ "badField": &graphql.FieldConfig{ Type: ttype, }, }, }) return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: badInterfaceType, }, }, }), }) }
func schemaWithObjectImplementingType(implementedType *graphql.Interface) (graphql.Schema, error) { badObjectType := graphql.NewObject(graphql.ObjectConfig{ Name: "BadObject", Interfaces: []*graphql.Interface{implementedType}, Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: graphql.String, }, }, }) return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: badObjectType, }, }, }), }) }
func TestIntrospection_SupportsThe__TypeRootField(t *testing.T) { testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.FieldConfigMap{ "testField": &graphql.FieldConfig{ Type: graphql.String, }, }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: testType, }) if err != nil { t.Fatalf("Error creating Schema: %v", err.Error()) } query := ` { __type(name: "TestType") { name } } ` expected := &graphql.Result{ Data: map[string]interface{}{ "__type": map[string]interface{}{ "name": "TestType", }, }, } result := g(t, graphql.Params{ Schema: schema, RequestString: query, }) if !reflect.DeepEqual(expected, result) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } }
func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichDefinesAnObjectTypeTwice(t *testing.T) { a := graphql.NewObject(graphql.ObjectConfig{ Name: "SameName", Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: graphql.String, }, }, }) b := graphql.NewObject(graphql.ObjectConfig{ Name: "SameName", Fields: graphql.FieldConfigMap{ "f": &graphql.FieldConfig{ Type: graphql.String, }, }, }) queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "a": &graphql.FieldConfig{ Type: a, }, "b": &graphql.FieldConfig{ Type: b, }, }, }) _, err := graphql.NewSchema(graphql.SchemaConfig{ Query: queryType, }) expectedError := `Schema must contain unique named types but contains multiple types named "SameName".` if err == nil || err.Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, err) } }
Type: graphql.String, }, "nonNullSync": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.String), }, "promise": &graphql.FieldConfig{ Type: graphql.String, }, "nonNullPromise": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.String), }, }, }) var nonNullTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Query: dataType, }) func init() { throwingData["nest"] = func() interface{} { return throwingData } throwingData["nonNullNest"] = func() interface{} { return throwingData } throwingData["promiseNest"] = func() interface{} { return throwingData } throwingData["nonNullPromiseNest"] = func() interface{} { return throwingData }
func init() { Luke = StarWarsChar{ Id: "1000", Name: "Luke Skywalker", AppearsIn: []int{4, 5, 6}, HomePlanet: "Tatooine", } Vader = StarWarsChar{ Id: "1001", Name: "Darth Vader", AppearsIn: []int{4, 5, 6}, HomePlanet: "Tatooine", } Han = StarWarsChar{ Id: "1002", Name: "Han Solo", AppearsIn: []int{4, 5, 6}, } Leia = StarWarsChar{ Id: "1003", Name: "Leia Organa", AppearsIn: []int{4, 5, 6}, HomePlanet: "Alderaa", } Tarkin = StarWarsChar{ Id: "1004", Name: "Wilhuff Tarkin", AppearsIn: []int{4}, } Threepio = StarWarsChar{ Id: "2000", Name: "C-3PO", AppearsIn: []int{4, 5, 6}, PrimaryFunction: "Protocol", } Artoo = StarWarsChar{ Id: "2001", Name: "R2-D2", AppearsIn: []int{4, 5, 6}, PrimaryFunction: "Astromech", } Luke.Friends = append(Luke.Friends, []StarWarsChar{Han, Leia, Threepio, Artoo}...) Vader.Friends = append(Luke.Friends, []StarWarsChar{Tarkin}...) Han.Friends = append(Han.Friends, []StarWarsChar{Luke, Leia, Artoo}...) Leia.Friends = append(Leia.Friends, []StarWarsChar{Luke, Han, Threepio, Artoo}...) Tarkin.Friends = append(Tarkin.Friends, []StarWarsChar{Vader}...) Threepio.Friends = append(Threepio.Friends, []StarWarsChar{Luke, Han, Leia, Artoo}...) Artoo.Friends = append(Artoo.Friends, []StarWarsChar{Luke, Han, Leia}...) HumanData = map[int]StarWarsChar{ 1000: Luke, 1001: Vader, 1002: Han, 1003: Leia, 1004: Tarkin, } DroidData = map[int]StarWarsChar{ 2000: Threepio, 2001: Artoo, } episodeEnum := graphql.NewEnum(graphql.EnumConfig{ Name: "Episode", Description: "One of the films in the Star Wars Trilogy", Values: graphql.EnumValueConfigMap{ "NEWHOPE": &graphql.EnumValueConfig{ Value: 4, Description: "Released in 1977.", }, "EMPIRE": &graphql.EnumValueConfig{ Value: 5, Description: "Released in 1980.", }, "JEDI": &graphql.EnumValueConfig{ Value: 6, Description: "Released in 1983.", }, }, }) characterInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Character", Description: "A character in the Star Wars Trilogy", Fields: graphql.FieldConfigMap{ "id": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the character.", }, "name": &graphql.FieldConfig{ Type: graphql.String, Description: "The name of the character.", }, "appearsIn": &graphql.FieldConfig{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", }, }, ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { if character, ok := value.(StarWarsChar); ok { id, _ := strconv.Atoi(character.Id) human := GetHuman(id) if human.Id != "" { return humanType } } return droidType }, }) characterInterface.AddFieldConfig("friends", &graphql.FieldConfig{ Type: graphql.NewList(characterInterface), Description: "The friends of the character, or an empty list if they have none.", }) humanType = graphql.NewObject(graphql.ObjectConfig{ Name: "Human", Description: "A humanoid creature in the Star Wars universe.", Fields: graphql.FieldConfigMap{ "id": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the human.", Resolve: func(p graphql.GQLFRParams) interface{} { if human, ok := p.Source.(StarWarsChar); ok { return human.Id } return nil }, }, "name": &graphql.FieldConfig{ Type: graphql.String, Description: "The name of the human.", Resolve: func(p graphql.GQLFRParams) interface{} { if human, ok := p.Source.(StarWarsChar); ok { return human.Name } return nil }, }, "friends": &graphql.FieldConfig{ Type: graphql.NewList(characterInterface), Description: "The friends of the human, or an empty list if they have none.", Resolve: func(p graphql.GQLFRParams) interface{} { if human, ok := p.Source.(StarWarsChar); ok { return human.Friends } return []interface{}{} }, }, "appearsIn": &graphql.FieldConfig{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", Resolve: func(p graphql.GQLFRParams) interface{} { if human, ok := p.Source.(StarWarsChar); ok { return human.AppearsIn } return nil }, }, "homePlanet": &graphql.FieldConfig{ Type: graphql.String, Description: "The home planet of the human, or null if unknown.", Resolve: func(p graphql.GQLFRParams) interface{} { if human, ok := p.Source.(StarWarsChar); ok { return human.HomePlanet } return nil }, }, }, Interfaces: []*graphql.Interface{ characterInterface, }, }) droidType = graphql.NewObject(graphql.ObjectConfig{ Name: "Droid", Description: "A mechanical creature in the Star Wars universe.", Fields: graphql.FieldConfigMap{ "id": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the droid.", Resolve: func(p graphql.GQLFRParams) interface{} { if droid, ok := p.Source.(StarWarsChar); ok { return droid.Id } return nil }, }, "name": &graphql.FieldConfig{ Type: graphql.String, Description: "The name of the droid.", Resolve: func(p graphql.GQLFRParams) interface{} { if droid, ok := p.Source.(StarWarsChar); ok { return droid.Name } return nil }, }, "friends": &graphql.FieldConfig{ Type: graphql.NewList(characterInterface), Description: "The friends of the droid, or an empty list if they have none.", Resolve: func(p graphql.GQLFRParams) interface{} { if droid, ok := p.Source.(StarWarsChar); ok { friends := []map[string]interface{}{} for _, friend := range droid.Friends { friends = append(friends, map[string]interface{}{ "name": friend.Name, "id": friend.Id, }) } return droid.Friends } return []interface{}{} }, }, "appearsIn": &graphql.FieldConfig{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", Resolve: func(p graphql.GQLFRParams) interface{} { if droid, ok := p.Source.(StarWarsChar); ok { return droid.AppearsIn } return nil }, }, "primaryFunction": &graphql.FieldConfig{ Type: graphql.String, Description: "The primary function of the droid.", Resolve: func(p graphql.GQLFRParams) interface{} { if droid, ok := p.Source.(StarWarsChar); ok { return droid.PrimaryFunction } return nil }, }, }, Interfaces: []*graphql.Interface{ characterInterface, }, }) queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "hero": &graphql.FieldConfig{ Type: characterInterface, Args: graphql.FieldConfigArgument{ "episode": &graphql.ArgumentConfig{ Description: "If omitted, returns the hero of the whole saga. If " + "provided, returns the hero of that particular episode.", Type: episodeEnum, }, }, Resolve: func(p graphql.GQLFRParams) (r interface{}) { return GetHero(p.Args["episode"]) }, }, "human": &graphql.FieldConfig{ Type: humanType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Description: "id of the human", Type: graphql.NewNonNull(graphql.String), }, }, Resolve: func(p graphql.GQLFRParams) (r interface{}) { return GetHuman(p.Args["id"].(int)) }, }, "droid": &graphql.FieldConfig{ Type: droidType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Description: "id of the droid", Type: graphql.NewNonNull(graphql.String), }, }, Resolve: func(p graphql.GQLFRParams) (r interface{}) { return GetDroid(p.Args["id"].(int)) }, }, }, }) StarWarsSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Query: queryType, }) }
func TestExecutesUsingAComplexSchema(t *testing.T) { johnSmith = &testAuthor{ Id: 123, Name: "John Smith", Pic: func(width string, height string) *testPic { return getPic(123, width, height) }, RecentArticle: article("1"), } blogImage := graphql.NewObject(graphql.ObjectConfig{ Name: "Image", Fields: graphql.FieldConfigMap{ "url": &graphql.FieldConfig{ Type: graphql.String, }, "width": &graphql.FieldConfig{ Type: graphql.Int, }, "height": &graphql.FieldConfig{ Type: graphql.Int, }, }, }) blogAuthor := graphql.NewObject(graphql.ObjectConfig{ Name: "Author", Fields: graphql.FieldConfigMap{ "id": &graphql.FieldConfig{ Type: graphql.String, }, "name": &graphql.FieldConfig{ Type: graphql.String, }, "pic": &graphql.FieldConfig{ Type: blogImage, Args: graphql.FieldConfigArgument{ "width": &graphql.ArgumentConfig{ Type: graphql.Int, }, "height": &graphql.ArgumentConfig{ Type: graphql.Int, }, }, Resolve: func(p graphql.GQLFRParams) interface{} { 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 nil }, }, "recentArticle": &graphql.FieldConfig{}, }, }) blogArticle := graphql.NewObject(graphql.ObjectConfig{ Name: "Article", Fields: graphql.FieldConfigMap{ "id": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.String), }, "isPublished": &graphql.FieldConfig{ Type: graphql.Boolean, }, "author": &graphql.FieldConfig{ Type: blogAuthor, }, "title": &graphql.FieldConfig{ Type: graphql.String, }, "body": &graphql.FieldConfig{ Type: graphql.String, }, "keywords": &graphql.FieldConfig{ Type: graphql.NewList(graphql.String), }, }, }) blogAuthor.AddFieldConfig("recentArticle", &graphql.FieldConfig{ Type: blogArticle, }) blogQuery := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.FieldConfigMap{ "article": &graphql.FieldConfig{ Type: blogArticle, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Type: graphql.ID, }, }, Resolve: func(p graphql.GQLFRParams) interface{} { id := p.Args["id"] return article(id) }, }, "feed": &graphql.FieldConfig{ Type: graphql.NewList(blogArticle), Resolve: func(p graphql.GQLFRParams) interface{} { return []*testArticle{ article(1), article(2), article(3), article(4), article(5), article(6), article(7), article(8), article(9), article(10), } }, }, }, }) blogSchema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: blogQuery, }) if err != nil { t.Fatalf("Error in schema %v", err.Error()) } request := ` { feed { id, title }, article(id: "1") { ...articleFields, author { id, name, pic(width: 640, height: 480) { url, width, height }, recentArticle { ...articleFields, keywords } } } } fragment articleFields on Article { id, isPublished, title, body, hidden, notdefined } ` expected := &graphql.Result{ Data: map[string]interface{}{ "article": map[string]interface{}{ "title": "My Article 1", "body": "This is a post", "author": map[string]interface{}{ "id": "123", "name": "John Smith", "pic": map[string]interface{}{ "url": "cdn://123", "width": 640, "height": 480, }, "recentArticle": map[string]interface{}{ "id": "1", "isPublished": bool(true), "title": "My Article 1", "body": "This is a post", "keywords": []interface{}{ "foo", "bar", "1", "true", nil, }, }, }, "id": "1", "isPublished": bool(true), }, "feed": []interface{}{ map[string]interface{}{ "id": "1", "title": "My Article 1", }, map[string]interface{}{ "id": "2", "title": "My Article 2", }, map[string]interface{}{ "id": "3", "title": "My Article 3", }, map[string]interface{}{ "id": "4", "title": "My Article 4", }, map[string]interface{}{ "id": "5", "title": "My Article 5", }, map[string]interface{}{ "id": "6", "title": "My Article 6", }, map[string]interface{}{ "id": "7", "title": "My Article 7", }, map[string]interface{}{ "id": "8", "title": "My Article 8", }, map[string]interface{}{ "id": "9", "title": "My Article 9", }, map[string]interface{}{ "id": "10", "title": "My Article 10", }, }, }, } // parse query ast := testutil.TestParse(t, request) // execute ep := graphql.ExecuteParams{ Schema: blogSchema, AST: ast, } result := testutil.TestExecute(t, ep) if len(result.Errors) > 0 { t.Fatalf("wrong result, unexpected errors: %v", result.Errors) } if !reflect.DeepEqual(expected, result) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } }