Writing a simple e-comm REST API in Go programming language

Gautam Prajapati
8 min readNov 8, 2017

--

Image Source: https://golang.org/doc/gopher/fiveyears.jpg

In my quest of learning a new programming language for coding a server, I came across Go. As I started exploring more, I got to know pretty interesting concepts about Go which intensified my love to code a simple project in it.

Go is easy to learn and is said to be much faster than the popular backend languages like Python, Ruby, JS etc. This is because, Go is compiled directly to machine readable byte code but Python, for example, is slow because code is interpreted at runtime.

If you want to know more, I came across this article — Why you should learn Go? which digs into the technicalities in an interesting way.

The complete source code of this application lives on Github.

In this Article

  1. We will write a very basic e-commerce website API supporting basic CRUD(CREATE, READ, UPDATE and DELETE) operations and SEARCH on a predefined database of products.
  2. Populate a MongoDB database with dummy products and host it on mLab(Optional).
  3. Add Authentication based on JWT(JSON web Tokens) Tokens. Only Authenticated users will be able to Add, Update and Delete products from database.
  4. Deploy our simple Go application on Heroku.

The API documentation is available on Github.

Setup

Golang Development Setup

If you’re a fan of details, follow the official docs of installation. The process is quite easy.

I also came across this bash script to automate the Golang development setup:

  1. Download the script using wget or your fav download manager
$ wget https://raw.githubusercontent.com/canha/golang-tools-install-script/master/goinstall.sh 

2. According to the OS you’re on

  • Linux 64 bit -> bash goinstall.sh --64
  • Linux 32 bit -> bash goinstall.sh --32
  • macOS -> bash goinstall.sh --darwin

Project Setup

  1. Create a new folder rest-and-go in $GOPATH/src directory. If you have used the bash script for setup, your $GOPATH variable should point to $HOME/go
  2. Make your directory structure look like this —
rest-and-go/
|- store/ - Contains main API logic files
|- controller.go - Defines handler methods of endpoints
|- model.go - User and Product models
|- repository.go - Methods interacting with the database
|- router.go - Defines routes and endpoints
|- Procfile - Procfile for herkou deployment
|- README.md - Readme file for documentation
|- dummyData.js - Populates MongoDB with dummy data
|- main.go - Entry point of the API

3. We’re going to need some additional libraries for routing, interacting with MongoDB and authentication.

## Library to handle jwt authentication 
$ go get "github.com/dgrijalva/jwt-go"

## Libraries to handle network routing
$ go get "github.com/gorilla/mux"
$ go get "github.com/gorilla/context"
$ go get "github.com/gorilla/handlers"

## mgo library for handling MongoDB
$ go get "gopkg.in/mgo.v2"

4. In order to deploy our API on Heroku, we’ll need to use Git version control system. Commit your code on regular intervals and push to Github. If you’re unfamiliar with Git/Github, read this.

Data Storage

Let’s begin with the data storage. Every API needs a database to store the data it will be interacting with. Our API will be using a MongoDB database containing the list of dummy products.

First step would be to install the MongoDB from here. After that, open Terminal or cmd prompt in Windows and start the `mongo` server by —

$ mongod --fork --logpath $HOME

This command will allow mongodb server to be run as a daemon. In simpler words, you will be able to use same terminal window to execute other commands. The server will start by default on port 27017.

If you want to see the logs in terminal itself, you can simply do —

$ mongod

Without —-fork option, you’ll need a new Terminal tab to execute rest of the commands.

Inserting Dummy Data

Create a script file named dummyData.js containing product details of our online store—

use dummyStore;var bulk = db.store.initializeUnorderedBulkOp();bulk.insert(   { _id: 1, title: "Apple iMac Pro", image: "http:://example.com/p1.jpg", price: 5000, rating: 4 });
bulk.insert( { _id: 2, title: "Google Pixel 2", image: "http:://example.com/p2.jpg", price: 2000, rating: 5});
bulk.insert( { _id: 3, title: "Apple iPhone X", image: "http:://example.com/p3.jpg", price: 3000, rating: 5});
bulk.insert( { _id: 4, title: "Google Chromebook", image: "http:://example.com/p4.jpg", price: 4000, rating: 5});
bulk.insert( { _id: 5, title: "Microsoft Holo Lens", image: "http:://example.com/p5.jpg", price: 1000, rating: 4});
bulk.insert( { _id: 6, title: "Samsung Galaxy S8", image: "http:://example.com/p6.jpg", price: 3000, rating: 3});
bulk.execute();

Now run this command in Terminal after navigating to the project directory-

$ mongo < dummyData.js

Using this js script is one of the ways to create and populate a collection named store in MongoDB database dummyStore. MongoDB stores data as BSON documents (binary representation of JSON) in collections. MongoDB databases hold collections of documents.

Writing the API

We’ll start with coding our entry point of application — main.go

I have tried to comment the code as much as possible to make it self understandable.

main.go

The import statement specifies the packages you want to use in the code. Go doesn’t let you import packages unnecessarily. You must use the package you are importing, otherwise code won’t compile.

The code in main.go calls store.NewRouter() which initialises the various routes(endpoints) in our API. This function is defined in store/routes.go

Let’s take a look at some portion of code in router.go. The complete code is available on Github.

As you can see, the code is pretty intuitive to understand. We define a struct Route which defines various fields for our endpoints. Then we create an array of type Route and initialise with our endpoint details like Name, Request Method to be used, URL pattern and function which will handle the request on that URL.

We also need to define a Product model defining the attributes of a Product in database like Title, Image, Price etc. It is defined in store/model.go file.

Handler functions for endpoints are defined in store/controller.go file.

This snippet shows two handler functions —

  • Index() — It is called when root URL(for example-http://localhost:8000/) is opened. Index() calls the function GetProducts() to retrieve the list of all the products available in database. It converts the response from db to JSON format and writes it to the body of HTML page.
  • AddProduct() — It is called when we want to add a new product to database. It reads the data sent in the body of POST request, casts it to the type Product and sends the addition request to the database.

In store/router.go you must have observed some handler functions written as an argument inside another function named AuthenticationMiddleware. This is part of implementing Authentication which is discussed a bit later.

Similarly, there are more functions handling Update, Delete, Search calls in controller.go. The complete code can be found here.

To interact with the database, all these handler methods call functions defined in store/repository.go file—

AddProduct(), for example, dials and connect to the MongoDB server running on port 27017. After connecting, it inserts the product into the database received as argument. GetProducts() returns the list of all products from the database. The complete code of repository.go is available here.

Adding Authentication

We will implement authentication using JSON Web Tokens. A JSON Web Token (JWT) is a JSON object that is defined in RFC 7519 as a safe way to represent a set of information between two parties.

There are two parts in implementing authentication. For the first part, we have defined a route in store/router.go named /get-token which generates a new JWT token based on information(username & password) in request body.

After that, we have to write a middleware(handler) function to secure our API endpoints.

The function GetToken() generates the JWT token by reading the username and password from request body. A sample request via CURL looks like this —

curl -X POST \
-H "Content-Type: application/json" \
-d '{ username: "<YOUR_USERNAME>", password: "<RANDOM_PASSWORD>"}' \
BASE_URL/get-token

This request will return a JWT token which has to be sent as Authentication Header while making requests to add, update or delete products from the database.

AuthenticationMiddleware() is the function which verifies the JWT token coming from the authentication header of a request. If the token is verified, it gives up the payload to the handler function in its argument which then handles it accordingly.

We just have to wrap the AddProduct(), UpdateProduct(), DeleteProduct() handlers in AuthenticationMiddleware() and it’ll make sure they are secured.

Running the API

Yay! Now we’re ready to try out our API. Navigate to rest-and-go/ directory and execute—

$ export PORT=8000
$ go run main.go

Make sure PORT environment variable is defined before running main.go. go run will compile the main.go or throw errors to be solved, if any.

Now open http://localhost:8000/ to view the list of products as JSON. It is recommended to install some extension to beautify JSON(like JSON Formatter) if you’re trying in a browser.

Follow the API documentation to know more about making requests at various endpoints.

Creating and hosting MongoDB on mLab

If you don’t want the hassle of running Mongo every time on your system, you can create and host the database on mLab.

Disclaimer: I’m not associated with mLab in any way, I am recommending it because I found it pretty easy to create and host my MongoDB. You’re free to use any other service as well.

  1. Create a new account on mLab if you don’t have already.
  2. Add a new database subscription. mLab provides a free Sandbox database.
  3. Create a new database named dummyStore and a collection store in it.
  4. Add documents to your store collection. A document is nothing but your individual product data in JSON format. You can find the JSON here.

You should see something like this —

mLab Screenshot

5. Create a new User by going to Users tab. You’d need that username and password to communicate with db.

6. Copy the mongodb:// URL, use it with username & password you created in step 5 and paste it as mongo server URL at the place of http://localhost:27017 in store/repository.go.

7. If you used some different database name or collection name, make sure you update the DBNAME and COLLECTION variables accordingly.

Deploying on Heroku

  1. Sign up on Heroku.
  2. Download and install the Heroku CLI.
  3. Type $ heroku login in Terminal and login with your heroku credentials.
  4. Make sure you have committed your working code.
  5. Heroku will need to know our dependency packages to build the app on its server. Steps 6–8 shows how to export dependencies with Godep.
  6. Type $ go get github.com/kr/godep in Terminal.
  7. Save your dependencies with $ godep save. This will save a list of dependencies to the file Godeps/Godeps.json, and copy their source code into Godeps/_workspace.
  8. Add the Godeps/ directory to git and commit the changes.
  9. Create a text file named Procfile and it’s content should look exactly like this — web: rest-and-go.
  10. Now we’re ready to deploy our app to Heroku. Type $ heroku create in Terminal. It creates a new Heroku application in your account and adds Heroku repo URL as a git remote.
  11. Push the code to Heroku remote $ git push heroku master. Try the API with $ heroku open. If everything was fine, you would see the list of products as JSON in your browser.

References

--

--

Gautam Prajapati

Senior Software Engineer @Airbnb | Founder @CarbonMarketsHQ