func TestTypeSystem_DefinitionExample_ProhibitsNestingNonNullInsideNonNull(t *testing.T) { ttype := graphql.NewNonNull(graphql.NewNonNull(graphql.Int)) expected := `Can only create NonNull of a Nullable Type but got: Int!.` if ttype.Error().Error() != expected { t.Fatalf(`expected %v , got: %v`, expected, ttype.Error()) } }
func TestLists_NonNullListOfNonNullArrayOfFunc_ContainsNulls(t *testing.T) { ttype := graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(graphql.Int))) // `data` is a slice of functions that return values // Note that its uses the expected signature `func() interface{} {...}` data := []interface{}{ func() interface{} { return 1 }, func() interface{} { return nil }, func() interface{} { return 2 }, } expected := &graphql.Result{ Data: map[string]interface{}{ "nest": map[string]interface{}{ "test": []interface{}{ 1, nil, 2, }, }, }, } checkList(t, ttype, data, expected) }
func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWithAnEquivalentlyModifiedInterfaceField(t *testing.T) { anotherInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.NewNonNull(graphql.NewList(graphql.String)), }, }, }) anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.NewNonNull(graphql.NewList(graphql.String)), }, }, }) _, err := schemaWithObjectFieldOfType(anotherObject) if err != nil { t.Fatalf(`unexpected error: %v for type "%v"`, err, anotherObject) } }
func init() { nodeTestUserType = graphql.NewObject(graphql.ObjectConfig{ Name: "User", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.ID), }, "name": &graphql.Field{ Type: graphql.String, }, }, Interfaces: []*graphql.Interface{nodeTestDef.NodeInterface}, }) nodeTestPhotoType = graphql.NewObject(graphql.ObjectConfig{ Name: "Photo", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.ID), }, "width": &graphql.Field{ Type: graphql.Int, }, }, Interfaces: []*graphql.Interface{nodeTestDef.NodeInterface}, }) nodeTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Query: nodeTestQueryType, }) }
func TestLists_NonNullListOfNonNullFunc_ReturnsNull(t *testing.T) { ttype := graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(graphql.Int))) // `data` is a function that return values // Note that its uses the expected signature `func() interface{} {...}` data := func() interface{} { return nil } expected := &graphql.Result{ Data: map[string]interface{}{ "nest": nil, }, Errors: []gqlerrors.FormattedError{ { Message: "Cannot return null for non-nullable field DataType.test.", Locations: []location.SourceLocation{ { Line: 1, Column: 10, }, }, }, }, } checkList(t, ttype, data, expected) }
func PluralIdentifyingRootField(config PluralIdentifyingRootFieldConfig) *graphql.Field { inputArgs := graphql.FieldConfigArgument{} if config.ArgName != "" { inputArgs[config.ArgName] = &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(config.InputType))), } } return &graphql.Field{ Description: config.Description, Type: graphql.NewList(config.OutputType), Args: inputArgs, Resolve: func(p graphql.ResolveParams) (interface{}, error) { inputs, ok := p.Args[config.ArgName] if !ok { return nil, nil } if config.ResolveSingleInput == nil { return nil, nil } switch inputs := inputs.(type) { case []interface{}: res := []interface{}{} for _, input := range inputs { r := config.ResolveSingleInput(input) res = append(res, r) } return res, nil } return nil, nil }, } }
func TestTypeSystem_DefinitionExample_StringifiesSimpleTypes(t *testing.T) { type Test struct { ttype graphql.Type expected string } tests := []Test{ {graphql.Int, "Int"}, {blogArticle, "Article"}, {interfaceType, "Interface"}, {unionType, "Union"}, {enumType, "Enum"}, {inputObjectType, "InputObject"}, {graphql.NewNonNull(graphql.Int), "Int!"}, {graphql.NewList(graphql.Int), "[Int]"}, {graphql.NewNonNull(graphql.NewList(graphql.Int)), "[Int]!"}, {graphql.NewList(graphql.NewNonNull(graphql.Int)), "[Int!]"}, {graphql.NewList(graphql.NewList(graphql.Int)), "[[Int]]"}, } for _, test := range tests { ttypeStr := fmt.Sprintf("%v", test.ttype) if ttypeStr != test.expected { t.Fatalf(`expected %v , got: %v`, test.expected, ttypeStr) } } }
func MutationWithClientMutationID(config MutationConfig) *graphql.Field { augmentedInputFields := config.InputFields if augmentedInputFields == nil { augmentedInputFields = graphql.InputObjectConfigFieldMap{} } augmentedInputFields["clientMutationId"] = &graphql.InputObjectFieldConfig{ Type: graphql.NewNonNull(graphql.String), } augmentedOutputFields := config.OutputFields if augmentedOutputFields == nil { augmentedOutputFields = graphql.Fields{} } augmentedOutputFields["clientMutationId"] = &graphql.Field{ Type: graphql.NewNonNull(graphql.String), } inputType := graphql.NewInputObject(graphql.InputObjectConfig{ Name: config.Name + "Input", Fields: augmentedInputFields, }) outputType := graphql.NewObject(graphql.ObjectConfig{ Name: config.Name + "Payload", Fields: augmentedOutputFields, }) return &graphql.Field{ Name: config.Name, Type: outputType, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(inputType), }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { if config.MutateAndGetPayload == nil { return nil, nil } input := map[string]interface{}{} if inputVal, ok := p.Args["input"]; ok { if inputVal, ok := inputVal.(map[string]interface{}); ok { input = inputVal } } payload, err := config.MutateAndGetPayload(input, p.Info, p.Context) if err != nil { return nil, err } if clientMutationID, ok := input["clientMutationId"]; ok { payload["clientMutationId"] = clientMutationID } return payload, nil }, } }
func withModifiers(ttypes []graphql.Type) []graphql.Type { res := ttypes for _, ttype := range ttypes { res = append(res, graphql.NewList(ttype)) } for _, ttype := range ttypes { res = append(res, graphql.NewNonNull(ttype)) } for _, ttype := range ttypes { res = append(res, graphql.NewNonNull(graphql.NewList(ttype))) } return res }
func TestTypeSystem_NonNullMustAcceptGraphQLTypes_RejectsNilAsNonNullableType(t *testing.T) { result := graphql.NewNonNull(nil) expectedError := `Can only create NonNull of a Nullable Type but got: <nil>.` if result.Error() == nil || result.Error().Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, result.Error()) } }
func TestTypeSystem_DefinitionExample_IdentifiesOutputTypes(t *testing.T) { type Test struct { ttype graphql.Type expected bool } tests := []Test{ {graphql.Int, true}, {objectType, true}, {interfaceType, true}, {unionType, true}, {enumType, true}, {inputObjectType, false}, } for _, test := range tests { ttypeStr := fmt.Sprintf("%v", test.ttype) if graphql.IsOutputType(test.ttype) != test.expected { t.Fatalf(`expected %v , got: %v`, test.expected, ttypeStr) } if graphql.IsOutputType(graphql.NewList(test.ttype)) != test.expected { t.Fatalf(`expected %v , got: %v`, test.expected, ttypeStr) } if graphql.IsOutputType(graphql.NewNonNull(test.ttype)) != test.expected { t.Fatalf(`expected %v , got: %v`, test.expected, ttypeStr) } } }
func TestLists_NullableListOfNonNullObjects_ContainsNull(t *testing.T) { ttype := graphql.NewList(graphql.NewNonNull(graphql.Int)) data := []interface{}{ 1, nil, 2, } expected := &graphql.Result{ Data: map[string]interface{}{ "nest": map[string]interface{}{ "test": nil, }, }, Errors: []gqlerrors.FormattedError{ { Message: "Cannot return null for non-nullable field DataType.test.", Locations: []location.SourceLocation{ { Line: 1, Column: 10, }, }, }, }, } checkList(t, ttype, data, expected) }
/* Creates the configuration for an id field on a node, using `toGlobalId` to construct the ID from the provided typename. The type-specific ID is fetcher by calling idFetcher on the object, or if not provided, by accessing the `id` property on the object. */ func GlobalIDField(typeName string, idFetcher GlobalIDFetcherFn) *graphql.Field { return &graphql.Field{ Name: "id", Description: "The ID of an object", Type: graphql.NewNonNull(graphql.ID), Resolve: func(p graphql.ResolveParams) (interface{}, error) { id := "" if idFetcher != nil { fetched, err := idFetcher(p.Source, p.Info, p.Context) id = fmt.Sprintf("%v", fetched) if err != nil { return id, err } } else { // try to get from p.Source (data) var objMap interface{} b, _ := json.Marshal(p.Source) _ = json.Unmarshal(b, &objMap) switch obj := objMap.(type) { case map[string]interface{}: if iid, ok := obj["id"]; ok { id = fmt.Sprintf("%v", iid) } } } globalID := ToGlobalID(typeName, id) return globalID, nil }, } }
func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWithASupersetNullableInterfaceFieldType(t *testing.T) { anotherInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, }, }) anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.String, }, }, }) _, err := schemaWithFieldType(anotherObject) expectedError := `AnotherInterface.field expects type "String!" but AnotherObject.field provides type "String".` if err == nil || err.Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, err) } }
// Describe [T!]! Array<T> func TestLists_NonNullListOfNonNullObjects_ContainsValues(t *testing.T) { ttype := graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(graphql.Int))) data := []interface{}{ 1, 2, } expected := &graphql.Result{ Data: map[string]interface{}{ "nest": map[string]interface{}{ "test": []interface{}{ 1, 2, }, }, }, } checkList(t, ttype, data, expected) }
func ConnectionDefinitions(config ConnectionConfig) *GraphQLConnectionDefinitions { edgeType := graphql.NewObject(graphql.ObjectConfig{ Name: config.Name + "Edge", Description: "An edge in a connection", Fields: graphql.Fields{ "node": &graphql.Field{ Type: config.NodeType, Description: "The item at the end of the edge", }, "cursor": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: " cursor for use in pagination", }, }, }) for fieldName, fieldConfig := range config.EdgeFields { edgeType.AddFieldConfig(fieldName, fieldConfig) } connectionType := graphql.NewObject(graphql.ObjectConfig{ Name: config.Name + "Connection", Description: "A connection to a list of items.", Fields: graphql.Fields{ "pageInfo": &graphql.Field{ Type: graphql.NewNonNull(pageInfoType), Description: "Information to aid in pagination.", }, "edges": &graphql.Field{ Type: graphql.NewList(edgeType), Description: "Information to aid in pagination.", }, }, }) for fieldName, fieldConfig := range config.ConnectionFields { connectionType.AddFieldConfig(fieldName, fieldConfig) } return &GraphQLConnectionDefinitions{ EdgeType: edgeType, ConnectionType: connectionType, } }
func TestTypeSystem_NonNullMustAcceptGraphQLTypes_AcceptsAnTypeAsNullableTypeOfNonNull(t *testing.T) { nullableTypes := []graphql.Type{ graphql.String, someScalarType, someObjectType, someUnionType, someInterfaceType, someEnumType, someInputObject, graphql.NewList(graphql.String), graphql.NewList(graphql.NewNonNull(graphql.String)), } for _, ttype := range nullableTypes { result := graphql.NewNonNull(ttype) if result.Error() != nil { t.Fatalf(`unexpected error: %v for type "%v"`, result.Error(), ttype) } } }
func TestLists_NullableListOfNonNullObjects_ReturnsNull(t *testing.T) { ttype := graphql.NewList(graphql.NewNonNull(graphql.Int)) expected := &graphql.Result{ Data: map[string]interface{}{ "nest": map[string]interface{}{ "test": nil, }, }, } checkList(t, ttype, nil, expected) }
// Describe [T!]! Func()Array<T> // equivalent to Promise<Array<T>> func TestLists_NonNullListOfNonNullFunc_ContainsValues(t *testing.T) { ttype := graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(graphql.Int))) // `data` is a function that return values // Note that its uses the expected signature `func() interface{} {...}` data := func() interface{} { return []interface{}{ 1, 2, } } expected := &graphql.Result{ Data: map[string]interface{}{ "nest": map[string]interface{}{ "test": []interface{}{ 1, 2, }, }, }, } checkList(t, ttype, data, expected) }
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 } nullingData["nest"] = func() interface{} { return nullingData } nullingData["nonNullNest"] = func() interface{} { return nullingData } nullingData["promiseNest"] = func() interface{} { return nullingData } nullingData["nonNullPromiseNest"] = func() interface{} { return nullingData } dataType.AddFieldConfig("nest", &graphql.Field{ Type: dataType, }) dataType.AddFieldConfig("nonNullNest", &graphql.Field{ Type: graphql.NewNonNull(dataType), }) dataType.AddFieldConfig("promiseNest", &graphql.Field{ Type: dataType, }) dataType.AddFieldConfig("nonNullPromiseNest", &graphql.Field{ Type: graphql.NewNonNull(dataType), }) }
/* Given a function to map from an ID to an underlying object, and a function to map from an underlying object to the concrete GraphQLObjectType it corresponds to, constructs a `Node` interface that objects can implement, and a field config for a `node` root field. If the typeResolver is omitted, object resolution on the interface will be handled with the `isTypeOf` method on object types, as with any GraphQL interface without a provided `resolveType` method. */ func NewNodeDefinitions(config NodeDefinitionsConfig) *NodeDefinitions { nodeInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Node", Description: "An object with an ID", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.ID), Description: "The id of the object", }, }, ResolveType: config.TypeResolve, }) nodeField := &graphql.Field{ Name: "Node", Description: "Fetches an object given its ID", Type: nodeInterface, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.ID), Description: "The ID of an object", }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { if config.IDFetcher == nil { return nil, nil } id := "" if iid, ok := p.Args["id"]; ok { id = fmt.Sprintf("%v", iid) } return config.IDFetcher(id, p.Info, p.Context) }, } return &NodeDefinitions{ NodeInterface: nodeInterface, NodeField: nodeField, } }
func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWhichImplementsAnInterfaceFieldAlongWithAdditionalRequiredArguments(t *testing.T) { anotherInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { return nil }, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ Type: graphql.String, }, }, }, }, }) anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ Type: graphql.String, }, "anotherInput": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.String), }, }, }, }, }) _, err := schemaWithObjectFieldOfType(anotherObject) expectedError := `AnotherObject.field(anotherInput:) is of required type "String!" but is not also provided by the interface AnotherInterface.field.` if err == nil || err.Error() != expectedError { t.Fatalf("Expected error: %v, got %v", expectedError, err) } }
func TestDirectives_DirectiveArgNamesMustBeValid(t *testing.T) { invalidDirective := graphql.NewDirective(graphql.DirectiveConfig{ Name: "skip", Description: "Directs the executor to skip this field or fragment when the `if` " + "argument is true.", Args: graphql.FieldConfigArgument{ "123if": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.Boolean), Description: "Skipped when true.", }, }, Locations: []string{ graphql.DirectiveLocationField, graphql.DirectiveLocationFragmentSpread, graphql.DirectiveLocationInlineFragment, }, }) _, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.Fields{ "a": &graphql.Field{ Type: graphql.String, }, }, }), Directives: []*graphql.Directive{invalidDirective}, }) expectedErr := gqlerrors.FormattedError{ Message: `Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "123if" does not.`, Locations: []location.SourceLocation{}, } if !reflect.DeepEqual(expectedErr, err) { t.Fatalf("Expected error to be equal, got: %v", testutil.Diff(expectedErr, err)) } }
}, }, }) // root mutation var rootMutation = graphql.NewObject(graphql.ObjectConfig{ Name: "RootMutation", Fields: graphql.Fields{ /* curl -g 'http://localhost:8080/graphql?query=mutation+_{createTodo(text:"My+new+todo"){id,text,done}}' */ "createTodo": &graphql.Field{ Type: todoType, // the return type for this field Args: graphql.FieldConfigArgument{ "text": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.String), }, }, Resolve: func(params graphql.ResolveParams) (interface{}, error) { // marshall and cast the argument value text, _ := params.Args["text"].(string) // figure out new id newID := RandStringRunes(8) // perform mutation operation here // for e.g. create a Todo and save to DB. newTodo := Todo{ ID: newID, Text: text,
func init() { var beingInterface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Being", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, }, }) var petInterface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Pet", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, }, }) var canineInterface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Canine", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, }, }) var dogCommandEnum = graphql.NewEnum(graphql.EnumConfig{ Name: "DogCommand", Values: graphql.EnumValueConfigMap{ "SIT": &graphql.EnumValueConfig{ Value: 0, }, "HEEL": &graphql.EnumValueConfig{ Value: 1, }, "DOWN": &graphql.EnumValueConfig{ Value: 2, }, }, }) var dogType = graphql.NewObject(graphql.ObjectConfig{ Name: "Dog", IsTypeOf: func(p graphql.IsTypeOfParams) bool { return true }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, "nickname": &graphql.Field{ Type: graphql.String, }, "barkVolume": &graphql.Field{ Type: graphql.Int, }, "barks": &graphql.Field{ Type: graphql.Boolean, }, "doesKnowCommand": &graphql.Field{ Type: graphql.Boolean, Args: graphql.FieldConfigArgument{ "dogCommand": &graphql.ArgumentConfig{ Type: dogCommandEnum, }, }, }, "isHousetrained": &graphql.Field{ Type: graphql.Boolean, Args: graphql.FieldConfigArgument{ "atOtherHomes": &graphql.ArgumentConfig{ Type: graphql.Boolean, DefaultValue: true, }, }, }, "isAtLocation": &graphql.Field{ Type: graphql.Boolean, Args: graphql.FieldConfigArgument{ "x": &graphql.ArgumentConfig{ Type: graphql.Int, }, "y": &graphql.ArgumentConfig{ Type: graphql.Int, }, }, }, }, Interfaces: []*graphql.Interface{ beingInterface, petInterface, canineInterface, }, }) var furColorEnum = graphql.NewEnum(graphql.EnumConfig{ Name: "FurColor", Values: graphql.EnumValueConfigMap{ "BROWN": &graphql.EnumValueConfig{ Value: 0, }, "BLACK": &graphql.EnumValueConfig{ Value: 1, }, "TAN": &graphql.EnumValueConfig{ Value: 2, }, "SPOTTED": &graphql.EnumValueConfig{ Value: 3, }, }, }) var catType = graphql.NewObject(graphql.ObjectConfig{ Name: "Cat", IsTypeOf: func(p graphql.IsTypeOfParams) bool { return true }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, "nickname": &graphql.Field{ Type: graphql.String, }, "meowVolume": &graphql.Field{ Type: graphql.Int, }, "meows": &graphql.Field{ Type: graphql.Boolean, }, "furColor": &graphql.Field{ Type: furColorEnum, }, }, Interfaces: []*graphql.Interface{ beingInterface, petInterface, }, }) var catOrDogUnion = graphql.NewUnion(graphql.UnionConfig{ Name: "CatOrDog", Types: []*graphql.Object{ dogType, catType, }, ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { // not used for validation return nil }, }) var intelligentInterface = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Intelligent", Fields: graphql.Fields{ "iq": &graphql.Field{ Type: graphql.Int, }, }, }) var humanType = graphql.NewObject(graphql.ObjectConfig{ Name: "Human", IsTypeOf: func(p graphql.IsTypeOfParams) bool { return true }, Interfaces: []*graphql.Interface{ beingInterface, intelligentInterface, }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, "pets": &graphql.Field{ Type: graphql.NewList(petInterface), }, "iq": &graphql.Field{ Type: graphql.Int, }, }, }) humanType.AddFieldConfig("relatives", &graphql.Field{ Type: graphql.NewList(humanType), }) var alienType = graphql.NewObject(graphql.ObjectConfig{ Name: "Alien", IsTypeOf: func(p graphql.IsTypeOfParams) bool { return true }, Interfaces: []*graphql.Interface{ beingInterface, intelligentInterface, }, Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "surname": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, "iq": &graphql.Field{ Type: graphql.Int, }, "numEyes": &graphql.Field{ Type: graphql.Int, }, }, }) var dogOrHumanUnion = graphql.NewUnion(graphql.UnionConfig{ Name: "DogOrHuman", Types: []*graphql.Object{ dogType, humanType, }, ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { // not used for validation return nil }, }) var humanOrAlienUnion = graphql.NewUnion(graphql.UnionConfig{ Name: "HumanOrAlien", Types: []*graphql.Object{ alienType, humanType, }, ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { // not used for validation return nil }, }) var complexInputObject = graphql.NewInputObject(graphql.InputObjectConfig{ Name: "ComplexInput", Fields: graphql.InputObjectConfigFieldMap{ "requiredField": &graphql.InputObjectFieldConfig{ Type: graphql.NewNonNull(graphql.Boolean), }, "intField": &graphql.InputObjectFieldConfig{ Type: graphql.Int, }, "stringField": &graphql.InputObjectFieldConfig{ Type: graphql.String, }, "booleanField": &graphql.InputObjectFieldConfig{ Type: graphql.Boolean, }, "stringListField": &graphql.InputObjectFieldConfig{ Type: graphql.NewList(graphql.String), }, }, }) var complicatedArgs = graphql.NewObject(graphql.ObjectConfig{ Name: "ComplicatedArgs", // TODO List // TODO Coercion // TODO NotNulls Fields: graphql.Fields{ "intArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "intArg": &graphql.ArgumentConfig{ Type: graphql.Int, }, }, }, "nonNullIntArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "nonNullIntArg": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.Int), }, }, }, "stringArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "stringArg": &graphql.ArgumentConfig{ Type: graphql.String, }, }, }, "booleanArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "booleanArg": &graphql.ArgumentConfig{ Type: graphql.Boolean, }, }, }, "enumArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "enumArg": &graphql.ArgumentConfig{ Type: furColorEnum, }, }, }, "floatArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "floatArg": &graphql.ArgumentConfig{ Type: graphql.Float, }, }, }, "idArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "idArg": &graphql.ArgumentConfig{ Type: graphql.ID, }, }, }, "stringListArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "stringListArg": &graphql.ArgumentConfig{ Type: graphql.NewList(graphql.String), }, }, }, "complexArgField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "complexArg": &graphql.ArgumentConfig{ Type: complexInputObject, }, }, }, "multipleReqs": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "req1": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.Int), }, "req2": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.Int), }, }, }, "multipleOpts": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "opt1": &graphql.ArgumentConfig{ Type: graphql.Int, DefaultValue: 0, }, "opt2": &graphql.ArgumentConfig{ Type: graphql.Int, DefaultValue: 0, }, }, }, "multipleOptAndReq": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "req1": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.Int), }, "req2": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.Int), }, "opt1": &graphql.ArgumentConfig{ Type: graphql.Int, DefaultValue: 0, }, "opt2": &graphql.ArgumentConfig{ Type: graphql.Int, DefaultValue: 0, }, }, }, }, }) queryRoot := graphql.NewObject(graphql.ObjectConfig{ Name: "QueryRoot", Fields: graphql.Fields{ "human": &graphql.Field{ Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Type: graphql.ID, }, }, Type: humanType, }, "alien": &graphql.Field{ Type: alienType, }, "dog": &graphql.Field{ Type: dogType, }, "cat": &graphql.Field{ Type: catType, }, "pet": &graphql.Field{ Type: petInterface, }, "catOrDog": &graphql.Field{ Type: catOrDogUnion, }, "dogOrHuman": &graphql.Field{ Type: dogOrHumanUnion, }, "humanOrAlien": &graphql.Field{ Type: humanOrAlienUnion, }, "complicatedArgs": &graphql.Field{ Type: complicatedArgs, }, }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: queryRoot, Directives: []*graphql.Directive{ graphql.NewDirective(graphql.DirectiveConfig{ Name: "operationOnly", Locations: []string{graphql.DirectiveLocationQuery}, }), graphql.IncludeDirective, graphql.SkipDirective, }, Types: []graphql.Type{ catType, dogType, humanType, alienType, }, }) if err != nil { panic(err) } TestSchema = &schema }
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.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the character.", }, "name": &graphql.Field{ Type: graphql.String, Description: "The name of the character.", }, "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", }, }, ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { if character, ok := p.Value.(StarWarsChar); ok { id, _ := strconv.Atoi(character.ID) human := GetHuman(id) if human.ID != "" { return humanType } } return droidType }, }) characterInterface.AddFieldConfig("friends", &graphql.Field{ 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.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the human.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { return human.ID, nil } return nil, nil }, }, "name": &graphql.Field{ Type: graphql.String, Description: "The name of the human.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { return human.Name, 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{}, error) { if human, ok := p.Source.(StarWarsChar); ok { return human.Friends, nil } return []interface{}{}, nil }, }, "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { return human.AppearsIn, 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{}, error) { if human, ok := p.Source.(StarWarsChar); ok { return human.HomePlanet, nil } return nil, nil }, }, }, Interfaces: []*graphql.Interface{ characterInterface, }, }) droidType = graphql.NewObject(graphql.ObjectConfig{ Name: "Droid", Description: "A mechanical creature in the Star Wars universe.", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the droid.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { return droid.ID, nil } return nil, nil }, }, "name": &graphql.Field{ Type: graphql.String, Description: "The name of the droid.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { return droid.Name, 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{}, error) { 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, nil } return []interface{}{}, nil }, }, "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { return droid.AppearsIn, nil } return nil, nil }, }, "primaryFunction": &graphql.Field{ Type: graphql.String, Description: "The primary function of the droid.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { return droid.PrimaryFunction, nil } return nil, nil }, }, }, Interfaces: []*graphql.Interface{ characterInterface, }, }) queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "hero": &graphql.Field{ 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.ResolveParams) (interface{}, error) { return GetHero(p.Args["episode"]), nil }, }, "human": &graphql.Field{ Type: humanType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Description: "id of the human", Type: graphql.NewNonNull(graphql.String), }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { return GetHuman(p.Args["id"].(int)), nil }, }, "droid": &graphql.Field{ Type: droidType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Description: "id of the droid", Type: graphql.NewNonNull(graphql.String), }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { return GetDroid(p.Args["id"].(int)), nil }, }, }, }) StarWarsSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Query: queryType, }) }
} return nil }, }) var testInputObject *graphql.InputObject = graphql.NewInputObject(graphql.InputObjectConfig{ Name: "TestInputObject", Fields: graphql.InputObjectConfigFieldMap{ "a": &graphql.InputObjectFieldConfig{ Type: graphql.String, }, "b": &graphql.InputObjectFieldConfig{ Type: graphql.NewList(graphql.String), }, "c": &graphql.InputObjectFieldConfig{ Type: graphql.NewNonNull(graphql.String), }, "d": &graphql.InputObjectFieldConfig{ Type: testComplexScalar, }, }, }) var testNestedInputObject *graphql.InputObject = graphql.NewInputObject(graphql.InputObjectConfig{ Name: "TestNestedInputObject", Fields: graphql.InputObjectConfigFieldMap{ "na": &graphql.InputObjectFieldConfig{ Type: graphql.NewNonNull(testInputObject), }, "nb": &graphql.InputObjectFieldConfig{ Type: graphql.NewNonNull(graphql.String),
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.Fields{ "url": &graphql.Field{ Type: graphql.String, }, "width": &graphql.Field{ Type: graphql.Int, }, "height": &graphql.Field{ Type: graphql.Int, }, }, }) blogAuthor := graphql.NewObject(graphql.ObjectConfig{ Name: "Author", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.String, }, "name": &graphql.Field{ Type: graphql.String, }, "pic": &graphql.Field{ Type: blogImage, Args: graphql.FieldConfigArgument{ "width": &graphql.ArgumentConfig{ Type: graphql.Int, }, "height": &graphql.ArgumentConfig{ Type: graphql.Int, }, }, 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), nil } return nil, nil }, }, "recentArticle": &graphql.Field{}, }, }) blogArticle := graphql.NewObject(graphql.ObjectConfig{ Name: "Article", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, "isPublished": &graphql.Field{ Type: graphql.Boolean, }, "author": &graphql.Field{ Type: blogAuthor, }, "title": &graphql.Field{ Type: graphql.String, }, "body": &graphql.Field{ Type: graphql.String, }, "keywords": &graphql.Field{ Type: graphql.NewList(graphql.String), }, }, }) blogAuthor.AddFieldConfig("recentArticle", &graphql.Field{ Type: blogArticle, }) blogQuery := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "article": &graphql.Field{ Type: blogArticle, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Type: graphql.ID, }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { id := p.Args["id"] return article(id), nil }, }, "feed": &graphql.Field{ Type: graphql.NewList(blogArticle), Resolve: func(p graphql.ResolveParams) (interface{}, error) { return []*testArticle{ article(1), article(2), article(3), article(4), article(5), article(6), article(7), article(8), article(9), article(10), }, nil }, }, }, }) 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)) } }
func init() { /** * We get the node interface and field from the relay library. * * The first method is the way we resolve an ID to its object. The second is the * way we resolve an object that implements node to its type. */ nodeDefinitions = relay.NewNodeDefinitions(relay.NodeDefinitionsConfig{ IDFetcher: func(id string, info graphql.ResolveInfo, ctx context.Context) (interface{}, error) { // resolve id from global id resolvedID := relay.FromGlobalID(id) // based on id and its type, return the object switch resolvedID.Type { case "Faction": return GetFaction(resolvedID.ID), nil case "Ship": return GetShip(resolvedID.ID), nil default: return nil, errors.New("Unknown node type") } }, TypeResolve: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { // based on the type of the value, return GraphQLObjectType switch value.(type) { case *Faction: return factionType default: return shipType } }, }) /** * We define our basic ship type. * * This implements the following type system shorthand: * type Ship : Node { * id: String! * name: String * } */ shipType = graphql.NewObject(graphql.ObjectConfig{ Name: "Ship", Description: "A ship in the Star Wars saga", Fields: graphql.Fields{ "id": relay.GlobalIDField("Ship", nil), "name": &graphql.Field{ Type: graphql.String, Description: "The name of the ship.", }, }, Interfaces: []*graphql.Interface{ nodeDefinitions.NodeInterface, }, }) /** * We define a connection between a faction and its ships. * * connectionType implements the following type system shorthand: * type ShipConnection { * edges: [ShipEdge] * pageInfo: PageInfo! * } * * connectionType has an edges field - a list of edgeTypes that implement the * following type system shorthand: * type ShipEdge { * cursor: String! * node: Ship * } */ shipConnectionDefinition := relay.ConnectionDefinitions(relay.ConnectionConfig{ Name: "Ship", NodeType: shipType, }) /** * We define our faction type, which implements the node interface. * * This implements the following type system shorthand: * type Faction : Node { * id: String! * name: String * ships: ShipConnection * } */ factionType = graphql.NewObject(graphql.ObjectConfig{ Name: "Faction", Description: "A faction in the Star Wars saga", Fields: graphql.Fields{ "id": relay.GlobalIDField("Faction", nil), "name": &graphql.Field{ Type: graphql.String, Description: "The name of the faction.", }, "ships": &graphql.Field{ Type: shipConnectionDefinition.ConnectionType, Args: relay.ConnectionArgs, Resolve: func(p graphql.ResolveParams) (interface{}, error) { // convert args map[string]interface into ConnectionArguments args := relay.NewConnectionArguments(p.Args) // get ship objects from current faction ships := []interface{}{} if faction, ok := p.Source.(*Faction); ok { for _, shipId := range faction.Ships { ships = append(ships, GetShip(shipId)) } } // let relay library figure out the result, given // - the list of ships for this faction // - and the filter arguments (i.e. first, last, after, before) return relay.ConnectionFromArray(ships, args), nil }, }, }, Interfaces: []*graphql.Interface{ nodeDefinitions.NodeInterface, }, }) /** * This is the type that will be the root of our query, and the * entry point into our schema. * * This implements the following type system shorthand: * type Query { * rebels: Faction * empire: Faction * node(id: String!): Node * } */ queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "rebels": &graphql.Field{ Type: factionType, Resolve: func(p graphql.ResolveParams) (interface{}, error) { return GetRebels(), nil }, }, "empire": &graphql.Field{ Type: factionType, Resolve: func(p graphql.ResolveParams) (interface{}, error) { return GetEmpire(), nil }, }, "node": nodeDefinitions.NodeField, }, }) /** * This will return a GraphQLField for our ship * mutation. * * It creates these two types implicitly: * input IntroduceShipInput { * clientMutationID: string! * shipName: string! * factionId: ID! * } * * input IntroduceShipPayload { * clientMutationID: string! * ship: Ship * faction: Faction * } */ shipMutation := relay.MutationWithClientMutationID(relay.MutationConfig{ Name: "IntroduceShip", InputFields: graphql.InputObjectConfigFieldMap{ "shipName": &graphql.InputObjectFieldConfig{ Type: graphql.NewNonNull(graphql.String), }, "factionId": &graphql.InputObjectFieldConfig{ Type: graphql.NewNonNull(graphql.ID), }, }, OutputFields: graphql.Fields{ "ship": &graphql.Field{ Type: shipType, Resolve: func(p graphql.ResolveParams) (interface{}, error) { if payload, ok := p.Source.(map[string]interface{}); ok { return GetShip(payload["shipId"].(string)), nil } return nil, nil }, }, "faction": &graphql.Field{ Type: factionType, Resolve: func(p graphql.ResolveParams) (interface{}, error) { if payload, ok := p.Source.(map[string]interface{}); ok { return GetFaction(payload["factionId"].(string)), nil } return nil, nil }, }, }, MutateAndGetPayload: func(inputMap map[string]interface{}, info graphql.ResolveInfo, ctx context.Context) (map[string]interface{}, error) { // `inputMap` is a map with keys/fields as specified in `InputFields` // Note, that these fields were specified as non-nullables, so we can assume that it exists. shipName := inputMap["shipName"].(string) factionId := inputMap["factionId"].(string) // This mutation involves us creating (introducing) a new ship newShip := CreateShip(shipName, factionId) // return payload return map[string]interface{}{ "shipId": newShip.ID, "factionId": factionId, }, nil }, }) /** * This is the type that will be the root of our mutations, and the * entry point into performing writes in our schema. * * This implements the following type system shorthand: * type Mutation { * introduceShip(input IntroduceShipInput!): IntroduceShipPayload * } */ mutationType := graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", Fields: graphql.Fields{ "introduceShip": shipMutation, }, }) /** * Finally, we construct our schema (whose starting query type is the query * type we defined above) and export it. */ var err error Schema, err = graphql.NewSchema(graphql.SchemaConfig{ Query: queryType, Mutation: mutationType, }) if err != nil { // panic if there is an error in schema panic(err) } }
Cursor ConnectionCursor `json:"cursor"` } type GraphQLConnectionDefinitions struct { EdgeType *graphql.Object `json:"edgeType"` ConnectionType *graphql.Object `json:"connectionType"` } /* The common page info type used by all connections. */ var pageInfoType = graphql.NewObject(graphql.ObjectConfig{ Name: "PageInfo", Description: "Information about pagination in a connection.", Fields: graphql.Fields{ "hasNextPage": &graphql.Field{ Type: graphql.NewNonNull(graphql.Boolean), Description: "When paginating forwards, are there more items?", }, "hasPreviousPage": &graphql.Field{ Type: graphql.NewNonNull(graphql.Boolean), Description: "When paginating backwards, are there more items?", }, "startCursor": &graphql.Field{ Type: graphql.String, Description: "When paginating backwards, the cursor to continue.", }, "endCursor": &graphql.Field{ Type: graphql.String, Description: "When paginating forwards, the cursor to continue.", }, "offset": &graphql.Field{