Not too long ago I wrote about creating a chat application that used Angular 2 for the front-end and Golang for the back-end. The message communication between the two was possible because of websockets. In this example, any number of Angular 2 clients could connect to the Golang application and communicate with each other, but new clients could not see past messages. This is because the data wasn’t being saved after it was sent.

Couchbase Golang Chat

We’re going to expand upon the Golang application that was previously created and include Couchbase support so messages are saved after they are sent, then are loaded when new clients connect.

The Requirements

There are a few requirements to get this project going. They are as follows:

It is very important that you have the chat server working since much of what we see will be a revisit to what was done in the previous guide. Including a Couchbase NoSQL database will be trivial, but Couchbase with N1QL query support must already be installed.

Creating a Couchbase Server Bucket and Adding an Index

This project will require at least one bucket to be created in Couchbase. This bucket will hold all the message data sent to and from the Golang chat server. The data stored will look something like this:

You can choose to use the Couchbase default bucket or you can choose to create a new one. I’ll be using a bucket called example in this project.

Because querying will be involved we need to define at least one index that can be used on our bucket. This index can be created using the Couchbase Query Workbench or the Couchbase Shell (CBQ). Using one of those tools, execute the following:

With the index created, the application can be modified to include NoSQL storage.

Establishing a Connection to Couchbase Server

Before we can start saving data to Couchbase, a connection must be established from our Go application. If you’ve followed the previous guide, your Go application might be at a path similar to $GOPATH/src/github.com/nraboy/realtime-chat/main.go.

Before you open your source code file, you need to install the Golang SDK for Couchbase. It can be installed by executing:

With the Couchbase SDK installed, open $GOPATH/src/github.com/nraboy/realtime-chat/main.go and include the following line outside any functions:

We’ve included the variable outside any functions because we want it to be global to our application, not local to a particular function.

Inside the main function, before the goroutine of our client manager, we want to establish a connection to the cluster and open a particular bucket. This can be done through the following:

In the above scenario I’ve connected to my locally running node and opened the example bucket that was created previously.

At this point Couchbase is ready to be used and we can focus on our data model.

Defining the Couchbase JSON Data Model

We saw the proposed JSON data model previously, but we need to make it possible through Golang. This is done through the use of a Golang data structure.

Near the other existing data structures, include the following:

The above Message structure has properties mapped to JSON elements. One element which we’re not choosing to use, but would make sense to have is the Recipient. You never know if down the road you’ll want to send messages to specific clients.

Couchbase can work directly with the Message structure for both saving and reading data. To send it over a websocket, it can be marshaled into JSON.

Saving and Loading Messages with Couchbase

This brings us to making the saving and loading of data happen. We have the database setup with a connection established. We have our data model. Now let’s put it to use.

For simplicity we are going to keep every document id unique. This can be done through a UUID library which can be installed via the command line like so:

Within the application add a saveMessage method like the following:

Notice that we’re accepting a Message, generating a new document key, and upserting it into the database. This means every message will be stored as its own document.

So how about loading data when a connection is established?

In the above loadMessages method we accept a Client which will represent the freshly connected client. The client that wishes to obtain message history.

A N1QL query is created to fetch all messages and order them by the timestamp value. Each result of the query is marshaled into JSON and added to the client channel to be sent.

So how do we use these two methods?

When a websocket connection is established, the client manager registers the client for broadcasting. This happens in the project’s start method. In the start method there is a switch statement for client registration. Let’s modify it to look like the following:

Notice that after the client connection is registered, we take the connection and pass it to the loadMessages method that we had just created. This will send all previously stored messages to that particular client.

Saving the messages will be a little different.

In the previous tutorial we created a read method. Modify it to look like the following:

What is important is the following lines:

The server will receive a message from the client and construct an actual Message with additional information like who sent it and when. This message is then saved into the database.

Try running the Golang application again with the Angular 2 client. It should save the messages now.

Conclusion

We just saw how to add Couchbase to a previous websocket example that I wrote. In the previous example we had a client and server chat application that communicated using websockets. We expanded on this example and started saving the message data into Couchbase so it could be loaded by new chat participants.

Author

Posted by Madhuram Gupta

2 Comments

Leave a reply