Using GraphQL with Golang and a NoSQL Database

A few weeks ago I had mentioned that I was learning about the increasingly popular GraphQL and how it can be a replacement to the common RESTful API. In my previous example, we saw how to create a GraphQL application using Node.js and a Couchbase NoSQL database. However, I’m just as much a fan of the Go programming language as I am of Node.js.

We’re going to see how to create an application with Golang that can create and query for data using GraphQL queries rather than several RESTful API endpoints.

If you’re unfamiliar with GraphQL, it works by passing queries from a front-end to the backend and getting back only the data that you’ve requested, regardless on where it came from or how complex, rather than consuming data from any number of potentially unrelated API endpoints. This reduces your requests as well as your data payload, keeping things quick and efficient.

Getting Started with GraphQL and Golang

Like with a RESTful API, most of a GraphQL application will consist of setup. However, less of a GraphQL application will depend on planning, which is different from a RESTful API which requires heavy planning in order to remain easy to use.

We need to install a GraphQL package dependency for Golang before we can proceed. From the command line, execute the following:

1

go get github.com/graphql-go/graphql

With our dependency available, create a new project within your $GOPATH. Within that project, create a file called main.go and include the following which will be our application base:

Our plan is to create an application that can create and query accounts as well as create and query blog entries for any particular account. The data model for our application is defined by the Account struct and the Blog struct. This data model will help power our database data model as well as our GraphQL data model.

When it comes to the GraphQL setup, you’ll notice that there are a few objects created. The accountType and the blogType represent the GraphQL data model which will be crafted around the Go structs. They are not yet configured, but they will be. The rootQuery will be the set of queries we can run and the rootMutation will be any data changing mutation that can be run. With GraphQL, you’re not limited to just reading data.

The GraphQL schema allows us to define what are queries and what are mutations. This is required for when we wish to consume queries. Even though we’re not creating a RESTful API, we still need an HTTP endpoint. This single /graphql endpoint will handle all querying and mutations and is powered by the schema.

Before we hook up the database, we can define our GraphQL schema:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

accountType:=graphql.NewObject(graphql.ObjectConfig{

Name:"Account",

Fields:graphql.Fields{

"id":&graphql.Field{

Type:graphql.String,

},

"firstname":&graphql.Field{

Type:graphql.String,

},

"lastname":&graphql.Field{

Type:graphql.String,

},

},

})

blogType:=graphql.NewObject(graphql.ObjectConfig{

Name:"Blog",

Fields:graphql.Fields{

"id":&graphql.Field{

Type:graphql.String,

},

"account":&graphql.Field{

Type:graphql.String,

},

"title":&graphql.Field{

Type:graphql.String,

},

"content":&graphql.Field{

Type:graphql.String,

},

},

})

Notice that we’re only defining property names and their corresponding data type. I told you it would be pretty similar to how we’ve defined the data structures in Go.

Now let’s focus on loading our schema with data from Couchbase Server.

Querying Data from a NoSQL Database with GraphQL

As of right now we’ve done no database preparation. The point of this tutorial is not around configuring Couchbase. You’ll need Couchbase Server available with N1QL support, a Bucket, some indexes, and a role-based access control account for the application.

From the command line, execute the following lines to get our database packages:

1

2

go get github.com/satori/go.uuid

go get gopkg.in/couchbase/gocb.v1

The above commands will get us a package for creating UUID values for document keys as well as the Couchbase Go SDK.

Ignoring everything we’ve already done to our main.go file, take a look at the following code and fit it into what you have where it makes sense:

Notice that we have defined a Bucket that we’ll be using when interacting with the database. We’re connecting to a Couchbase cluster in the main function, authenticating with an RBAC account, and opening a Bucket, all of which should have been defined prior to starting this tutorial.

Let’s assume you’ve already got data in your database. We’re going to start by trying to query for data. Remember the following chunk of code that was previously added?

1

2

3

4

rootQuery:=graphql.NewObject(graphql.ObjectConfig{

Name:"Query",

Fields:graphql.Fields{},

})

Each field will exist as a field in the Fields property. Let’s say we want to get all the accounts from our database.

In the above code we’re creating a GraphQL field called accounts that will return a list of accountType when executed. The Resolve function is what does the heavy lifting. We can optionally pass query parameters, but for this particular field we are not. When trying to query for accounts, we are creating a N1QL query that returns all possible properties and results. The GraphQL query will determine which of those properties and results make it to the client.

Take the following front-end query that can be executed:

1

2

3

4

5

6

{

accounts{

id,

firstname

}

}

While we could get the id, firstname, and lastname, we are choosing to only get the id and firstname of our results. To actually run the query, we’d issue a cURL statement like this:

Let’s look at another possible GraphQL query. Let’s say we want to query for a particular account, not all accounts. We could create a field like the following:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

"account":&graphql.Field{

Type:accountType,

Args:graphql.FieldConfigArgument{

"id":&graphql.ArgumentConfig{

Type:graphql.NewNonNull(graphql.String),

},

},

Resolve:func(params graphql.ResolveParams)(interface{},error){

varaccount Account

account.ID=params.Args["id"].(string)

_,err:=bucket.Get(account.ID,&account)

iferr!=nil{

returnnil,err

}

returnaccount,nil

},

},

This field when queried will return a single accountType, but there are arguments that can be passed. We’re requiring that an id be present and we’re requiring that it be a string. In the Resolve, we can get the id parameter and use it to get a NoSQL document by the document key. The result is returned and the GraphQL query determines what properties are sent back to the client.

Take the following query:

1

2

3

4

5

6

{

account(id:"2345345435"){

firstname,

lastname

}

}

In the above query, we pass an ID and choose to only return the firstname and lastname of the results. To actually run this query, we can issue a cURL statement like the following:

Now let’s say that we want to return all blogs for a particular user account. The steps will be similar to what we saw when querying for a particular account. The following would exist as a field in our rootQuery:

The result will be a list of blogType and we’re expecting a required account parameter to be passed in string format. Inside the Resolve function we can get the account value and use it in a parameterized N1QL query. The query will return all blog entries only for a particular account based on the account value.

The query for getting all blogs might look like the following:

1

2

3

4

5

6

{

blogs(account:"2345345435"){

id,

title

}

}

The above looks pretty similar to what we saw when querying for a particular account. We’re expecting a variable and we’re choosing to only return the id and the title properties.

Want to see a pretty neat query based on what we have so far? Check out the following query:

1

2

3

4

5

6

7

8

9

10

{

account(id:"2345345435"){

firstname,

lastname

}

blogs(account:"2345345435"){

title,

content

}

}

In the above example we’re making a single request. It is a single query, but we’re asking for account data and blog data for a particular account. Had we done this with a RESTful API we would have made several requests to our server and made potential application level mutations.

Now I could go ahead and continue creating fields that do querying or mutations, but the steps are the same. I’ll leave it to your imagination to continue contributing to this particular application idea.

Conclusion

You just saw how to use GraphQL to query for data in a Golang application that uses a NoSQL database. GraphQL is very useful if you want to let the user define what data they want in a single request rather than tirelessly creating multiple RESTful API endpoints that the user must keep track of. It is important to note that GraphQL is not a replacement when it comes to your application querying your database. You’ll still need to create proper N1QL queries in Couchbase. GraphQL only operates from a client level.

Posted by Nic Raboy, Developer Advocate, Couchbase

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.