Using Couchbase Server In A Golang Web Application

Not too long ago I wrote an article regarding how to create a RESTful API using the Go programming language, but in it I only used mock data rather than an actual database.  What happens if we want to use a database with GoLang?  What database, or more importantly, what kind of database should be used?  Most APIs transfer data in JSON format, so it might make sense to store data in the same format.  This means that a relational database might not make sense.  Instead, NoSQL databases fit quite well when it comes to RESTful APIs.  A popular NoSQL database that stores data in JSON format is the open source Couchbase Server.

We’re going to take a look at how to include Couchbase Server into our RESTful web application written in the Go programming language.

The RESTful API example I wrote previously is going to be the foundation to this tutorial, so if you haven’t checked it out, I definitely recommend you do.  However, you won’t be completely lost if you don’t as I’m going to try to relay all the necessary information.

At this point I’m going to assume you have GoLang installed and configured on your machine.

Creating a New Project with Dependencies

We’re going to create a new GoLang project for simplicity.  Using the Terminal (Mac and Linux) or Command Prompt (Windows), execute the following:

Essentially I just created those directories with the command above.  If the command doesn’t work on your operating system, create them manually.

Inside our project directory, we’re going to be working with a file called main.go.  It will be the only file in our project.  Before we start coding, we should probably download any project dependencies.

From the Command Prompt or Terminal, execute the following:

The dependencies above include a package for generating UUID values that we’ll use for document ids, the Couchbase Go SDK, and Mux for expanding the routing capabilities of our HTTP server.

Configuring Couchbase Server for the GoLang Project

Before we can start coding we need to make sure Couchbase Server is configured and ready for use.  We won’t be seeing how to install Couchbase Server.  If you are using a Mac, Linux, or Windows machine, you can see one of the available getting started guides for installation.  Instead we’ll be configuring a bucket for storing all the NoSQL documents for our application.

The goal here is to create a Couchbase bucket called restful-sample that has appropriate indexes for performing N1QL queries via our application code.

Inside the Couchbase administrative dashboard, choose Data Buckets and then choose Create New Data Bucket.  Give the new bucket a name and define a storage capacity.

Couchbase Server Create Bucket

Next we need to create indexes for this new bucket.

When it comes to creating indexes there are a few ways to do this.  If you’re using Couchbase 4.5 or higher you can use the Query Workbench.  In the Query Workbench execute the following query:

At least one index is required to use N1QL.  More indexes that have deeper complexity than the one I demonstrated will result in faster querying.

Couchbase Server Create Primary Index

If you don’t have Couchbase Server 4.5 or higher installed, a different strategy must be used for creating indexes.  You must use the Couchbase Query Shell (CBQ) that ships with Couchbase Server 4.0 and higher.  For information on how to access it, you can visit here.  The same query used in the Query Workbench should be used in the shell.

At this point we can focus on the actual application.

Designing the RESTful Web Application

With all the setup out of the way we can start coding the application.  This application will have five basic endpoints for handling information about people.  This is a standard create, retrieve, update, and delete (CRUD) application.  Each endpoint will communicate with the NoSQL database differently.

Inside the project’s $GOPATH/src/github.com/nraboy/cbproject/main.go file, add the following code:

There is a lot going on in the above code so it would be a good idea to break it down.

The first thing we’re doing is importing all the dependencies that we downloaded earlier in this article.  With the dependencies included in the project we can define two structs that will represent the JSON data that we work with.  The Person struct will have the essential information about a particular person and it will be saved like this as a JSON document in the database.  When querying data, result sets are wrapped in a parent JSON object, thus the need for the N1qlPerson struct.  Data will look like this when queried:

Inside the structs you’ll notice the use of the omitempty tag.  This means that if any property is empty or null, it will not be included in the JSON result.

Before we jump into the endpoint functions we have the following:

This bucket variable is defined outside the main function making it global to the application.  This will represent our open Couchbase bucket and be used when querying data.

Let’s skip down to the project’s main function:

In the above main function we define our application router and establish a connection to our Couchbase cluster.  In this case the Couchbase cluster is being run locally on my machine.  With the Couchbase cluster connection established we can open a particular bucket.  The bucket we use in this application will be called restful-sample.

There are five different routes in this application.  There is a route for getting all documents, a route for getting a single document, a route for creating a document, a route for updating a document, and finally a route for deleting a document.  Notice that each of these routes use GETPUTPOST, or DELETE.  Let’s take a look at each of the endpoint functions that go with each of the routes.

The above GetPersonEndpoint function will get a single person from the database.  The document id from the meta information is being compared against the document id parameter that was passed in with the route request.  This query is a parameterized query to prevent SQL injection.  We are returning JSON data with only the Person struct, not the entire N1qlPerson struct.

The above GetPeopleEndpoint function is similar to the previous, but this time we are expecting a slice of results rather than a single result.

The create, update, and delete functions follow pretty much the same strategy, making things very easy to maintain and understand.

At this point the applicant can be run.  When it comes to testing you’ll have to use cURL, Postman, or similar since the web browser cannot typically test PUTPOST, or DELETE endpoints out of the box.

Conclusion

You just saw how to take our previous RESTful API GoLang example to the next level by including Couchbase Server as our NoSQL document database.  When using Couchbase, we are able to run SQL-like queries called N1QL queries to work with any data in the database.  Although we don’t have to use these N1QL queries, it makes things very easy and reduces a lot of potential parsing code.

A video version of this article can be seen below.

Nic Raboy

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.

  • artbikes

    I am running across this error when hitting the /people endpoint — any ideas? (Cut and pasted your code above)
    http: panic serving [::1]:57809: runtime error: invalid memory address or nil pointer dereference

    • So runtime error. Are the other end points working?

      • artbikes

        I am able to create documents with PUTs to /person. None of the GETs are working for me.

        • artbikes

          Fixed it. Must have missed the part about creating an index while following along with video. Installed the Query Workbench, create the index as mentioned here — works like a charm.

          • Awesome! Was just going to mention that shortly. N1QL queries rely on at least one index. The more specific the index, the faster the queries.

  • IHateHipsters

    Thanks for the tutorial Nic. I don’t know about other versions of Go but for 1.8 I had to add an identifier to the import of go.uuid:
    import (
    uuid “github.com/satori/go.uuid
    )

    Cheers!

    • Ah you know what. I think I forgot that step in my guide. I’m so used to my editor, Atom, downloading the dependencies for me.

      Anyways, thanks for pointing it out!