Go GraphQL: Implementing the GraphQL Queries in Golang #3

In this post, we will learn how to write GraphQL Query resolvers for our queries



In this section, you are going to implement the first API operation that provides the functionality for a Star Wars API, We will add wars character Human.


. . .

Extending the schema definition

In general, when adding a new feature to the API, the process will look pretty similar every time:
  1. Extend the GraphQL schema definition with a new root field (and new data types, if needed)
  2. Implement corresponding resolver functions for the added fields

This process is also referred to as schema-driven or schema-first development.
So, let’s go ahead and tackle the first step, extending the GraphQL schema definition.

A ) Get List of All Humans
Let’s start by implementing a humans query that allows you to retrieve a list of star wars Human elements.

1. Define Schema
So, let’s go ahead and tackle the first step, extending the GraphQL schema definition by adding the Human type.

var 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.",
},
"name": &graphql.Field{
Type: graphql.String,
Description: "The name of the human.",
},
"appearsIn": &graphql.Field{
Type: graphql.NewList(episodeEnum),
Description: "Which movies they appear in.",
},
"homePlanet": &graphql.Field{
Type: graphql.String,
Description: "The home planet of the human, or null if unknown.",
},
},
})

Pretty straightforward. You’re defining a new Human that represents a Human of star wars. Each HumanType has an id, a name homePlanet planet. appearsIn is a list of episode enums

You’re then adding another root field to the Query type that allows you to retrieve a list of Human elements.

2. Implement resolver functions
The next step is to implement the resolver function for the humans query. In fact, one thing we haven’t mentioned yet is that not only root fields, but virtually all fields on the types in a GraphQL schema have resolver functions.

You’re adding a new resolver for the feed root field. Notice that a resolver always has to be named after the corresponding field from the schema definition.
Query := graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"humans": &graphql.Field{
Type: graphql.NewList(types.HumanType),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return resolvers.GetHumans(), nil
},
},
},
})

A new field of humans is added which returns the list of Humans, with respective resolvers function
#1
type StarWarsChar struct {
ID int
Name string
Friends []StarWarsChar
AppearsIn []int
HomePlanet string
PrimaryFunction string
}

#2
var HumanData = []StarWarsChar{
StarWarsChar{
ID: 1000,
Name: "Luke Skywalker",
AppearsIn: []int{4, 5, 6},
HomePlanet: "Tatooine",
},
..more data
}

#3
func GetHumans() []StarWarsChar {
return HumanData
}

Let’s walk through the numbered comments again:
  1. StarWarsChar is struct to hold Human data
  2. The HumanData variable is used to store the Humans at runtime. For now, everything is stored only in-memory rather than being persisted in a database.
  3. GetHumans is the function which returns the list of Humans

Go ahead and test the implementation by restarting the server (first use CTRL+C to stop the server if it is still running, then execute go run main.go again) and navigate to http://localhost:8080in your browser. If you expand the documentation of the Playground, you’ll notice that another query called humans is now available:


Try it out by sending the following query:
{
humans {
id
name
appearsIn
homePlanet
}
}

Awesome, the server responds with the data you defined in Human:
{
"data": {
"humans": [
{
"appearsIn": [
"NEWHOPE",
"EMPIRE",
"JEDI"
],
"homePlanet": "Tatooine",
"id": "1000",
"name": "Luke Skywalker"
},
{
"appearsIn": [
"NEWHOPE",
"EMPIRE",
"JEDI"
],
"homePlanet": "Tatooine",
"id": "1001",
"name": "Darth Vader"
},
{
"appearsIn": [
"NEWHOPE",
"EMPIRE",
"JEDI"
],
"homePlanet": "Alderaa",
"id": "1002",
"name": "Han Solo"
},
{
"appearsIn": [
"NEWHOPE",
"EMPIRE",
"JEDI"
],
"homePlanet": "Alderaa",
"id": "1003",
"name": "Leia Organa"
},
{
"appearsIn": [
"NEWHOPE"
],
"homePlanet": "Alderaa",
"id": "1004",
"name": "Wilhuff Tarkin"
}
]
}
}

Feel free to play around with the query by removing any fields from the selection set and observe the responses sent by the server.
. . .
B ) Get Human by ID
We will pass the human ID into the resolver function and it should return the appropriate Human, let's write some code

1. Define Schema
We will use the same schema previously defined for the HymanType
go-greaphql-part-2/after/types/types.go var HumanType = graphql.NewObject(graphql.ObjectConfig{ Name: "Human", Description: "A humanoid creature in the Star Wars universe.", Fields: graphql.Fields{ ... fields }, })

2. Implement resolver functions
The next step is to implement the resolver function for the human query. It will accept the human id as parameter

Query := graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"human": &graphql.Field{
Type: types.HumanType,
#1
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Description: "id of the human",
Type:graphql.NewNonNull(graphql.String),
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
#2
id, err := strconv.Atoi(p.Args["id"].(string))
if err != nil {
return nil, err
}
return resolvers.GetHuman(id), nil
},
},
},
})
Let's walk through the comments to understand
  1. Id can be defined inside the human field which is required and not null, Type of id arg is a string
  2. Resolver function will receive the args that can be passed to the actual function that lookup the human by id and returns the appropriate human data.

Go ahead and test the implementation by restarting the server (first use CTRL+C to stop the server if it is still running, then execute go run main.go again) and navigate to http://localhost:8080 in your browser. If you expand the documentation of the Playground, you’ll notice that another query called human is now available:


Try it out by sending the following query:
{
human (id:"1001") {
id
name
appearsIn
homePlanet
}
}

Awesome, the server responds with the data you defined in Human:
{
"data": {
"human": {
"appearsIn": [
"NEWHOPE",
"EMPIRE",
"JEDI"
],
"homePlanet": "Tatooine",
"id": "1001",
"name": "Darth Vader"
}
}
}
. . .


Never miss a post from Gufran Mirza, when you sign up for Ednsquare.