Develop REST API using Go and Test using various methods
Tags: go, tutorial, restapi, showdev
Published: 2020-07-24 11:36:40

## Table of Contents
- [Introduction](#introduction)
  - [Objective](#objective)
  - [What is REST API?](#what-is-rest-api)
  - [What makes a RESTful API?](#what-makes-a-restful-api)
    - [API Endpoint URL](#api-endpoint-url)
    - [HTTP Request Method](#http-request-method)
    - [The Response](#the-response)
- [Develop REST API using Go](#develop-rest-api-using-go)
  - [Why to choose Go for REST API?](#why-to-choose-go-for-rest-api)
  - [Go modules for REST API creation](#go-modules-for-rest-api-creation)
  - [Setup Golang development environment](#setup-golang-development-environment)
  - [Start development](#start-development)
    - [In function main](#in-function-main)
    - [POST and GET methods](#post-and-get-methods)
    - [Full Go source for REST API](#full-go-source-for-rest-api)
    - [Build the code](#build-the-code)
    - [Unit Testing of Go REST API](#unit-testing-of-go-rest-api)
- [REST API RealTime Testing](#rest-api-realtime-testing)
  - [Ngrok method](#ngrok-method)
  - [Test via Curl](#test-via-curl)
  - [Deploy API using docker container](#deploy-api-using-docker-container)
  - [Deploy using Google Cloud Kubernetes Cluster](#deploy-using-google-cloud-kubernetes-cluster)

## **Introduction**
- In my [previous blog](https://dev.to/chefgs/go-hello-world-program-17pk), we have developed `Hello World!` program in Go. 
- We will see, how to develop REST API using Golang in this article.

## Objective
- We will create a simple REST API, which runs on the `localhost` port `4000`
- We will also see, how to test the REST API endpoint in Real Time using various methods.

## **What is REST API?**
REST is acronym for REpresentational State Transfer. It is architectural style for distributed hypermedia systems and was first presented by Roy Fielding in 2000 in his famous dissertation.

Like any other architectural style, REST also does have it’s own 6 guiding constraints which must be satisfied if an interface needs to be referred as RESTful. These principles are listed below.

REST is not a standard but a set of recommendations and constraints for RESTful web services. 

These include:

- **Client-Server**: SystemA makes an HTTP request to a URL hosted by SystemB, which returns a response. 
It’s identical to how a browser works. The application makes a request for a specific URL. The request is routed to a web server that returns an HTML page. That page may contain references to images, style sheets, and JavaScript, which incur further requests and responses.

- **Stateless**: REST is stateless: the client request should contain all the information necessary to respond to a request. 
In other words, it should be possible to make two or more HTTP requests in any order and the same responses will be received.

- **Cacheable**: A response should be defined as cacheable or not.

- **Layered**: The requesting client need not know whether it’s communicating with the actual server, a proxy, or any other intermediary.

- **Uniform interface** – REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state.

- **Code on demand** (optional) – REST allows client functionality to be extended by downloading and executing code in the form of applets or scripts. This simplifies clients by reducing the number of features required to be pre-implemented.

## **What makes a RESTful API?**
A REST API consists of,
1. API Endpoint URL
2. HTTP Request Method (or Verb)
3. The Response returned from API request

### API Endpoint URL
An application implementing a RESTful API will define one or more URL endpoints with a domain, port, path, and/or querystring — for example, `https://somedomain:port/book/bookname?format=json`
Where, 
`https://somedomain` - Domain
`port` - Port number on which the API exposed
`/book` - Route Path
`bookname?format=json` - Query String

### HTTP Request Method
The above defined API endpoint URL will be serving HTTP methods, which can be perform create, read, update and delete functions defined within the application.

- GET	- read -	returns requested data
- POST - create -	creates a new record
- PUT - update - updates an existing record
- DELETE - delete -	deletes an existing record

### The Response
The response payload can be whatever is practical: data, HTML, an image, an audio file, and so on. Data responses are typically JSON-encoded, but XML, CSV, simple strings, or any other format can be used. You could allow the return format to be specified in the request either in JSON or XML format.

Each response header returns either of the HTTP status codes,
```
200 OK
201 Created
400 Bad Request
404 Not Found
401 Unauthorized
500 Internal server error
```
# **Develop REST API using Go**
## Why to choose Go for REST API?
- It is fast
- It is simple to understand
- It is compiled and works well with Microservices

## Go modules for REST API creation
We will be using below modules for our development
- `net/http`
- [**`Gin-gonic`**](https://github.com/gin-gonic/gin) REST API framework. It is a Go opensource utility module, which can be readily available to use and provides extensive REST API features in Go.
It provides the `REST API controller framework` for our code.

## Setup Golang development environment
- Refer the [DevTo Article Here](https://dev.to/chefgs/getting-started-with-go-in-ubuntu-16-04-3b59), to setup Golang dev environment.

## Start development
- Create directory to develop Golang api
```
cd $GOHOME/src
mkdir api
```
- Create file `api.go` in `api` directory
- Every go code starts with package name definition
`package main`

- Then we need to declare the module import section
```go
import (
  "fmt"
  "net/http"
  "github.com/gin-gonic/gin"
)
```
### In function main
- Add gin controller to handle the HTTP events coming to API

`router := gin.Default()`

- Add functions to handle the POST and GET requests on URL route path "/"
```go
  router.POST("/", PostMethod)
  router.GET("/", GetMethod)
```

- Listen to the specified port of localhost
```go
  listenPort := "4000"
  // Listen and Server on the LocalHost:Port
  router.Run(":"+listenPort)
```

### POST and GET methods
Define the Post and Get methods to handle the requests coming to API in "/" route path

```go
func PostMethod(c *gin.Context) {
  fmt.Println("\napi.go 'PostMethod' called")
  message := "PostMethod called"
  c.JSON(http.StatusOK, message)
}

func GetMethod(c *gin.Context) {
  fmt.Println("\napi.go 'GetMethod' called")
  message := "GetMethod called"
  c.JSON(http.StatusOK, message)
}
```
### Full Go source for REST API
Please find the [source code here](https://github.com/chefgs/golang/tree/master/src/api)
```go
// Golang REST API program
package main

import (
  "fmt"
  "net/http"
  "github.com/gin-gonic/gin"
)

func PostMethod(c *gin.Context) {
  fmt.Println("\napi.go 'PostMethod' called")
  message := "PostMethod called"
  c.JSON(http.StatusOK, message)
}

func GetMethod(c *gin.Context) {
  fmt.Println("\napi.go 'GetMethod' called")
  message := "GetMethod called"
  c.JSON(http.StatusOK, message)
}

func main() {
  router := gin.Default()

  router.POST("/", PostMethod)
  router.GET("/", GetMethod)

  listenPort := "4000"
  // Listen and Server on the LocalHost:Port
  router.Run(":"+listenPort)
}
```

### Build the code
Use the below commands to compile and build Go source,
```
go mod init api
go get -d "github.com/gin-gonic/gin"
go build api.go # to create the executable in current path
or
go install api.go # to create the executable in GOBIN path
go run api.go
```

### Unit Testing of Go REST API
- Please refer to the Unit testing code added `api_test.go`
- It uses the Go "testing" module 
- In order to test our `GetMethod` and `PostMethod` functions, we need to add the mock POST and GET request implemented in the code, by creating test functions `TestGetMethod` and `TestPostMethod`
- Here is the full source of `api_test.go`
```go
// Golang REST API unit testing program
package main

import (
  "testing"
  "net/http"
  "net/http/httptest"
  "fmt"
  "github.com/gin-gonic/gin"
)

func TestPostMethod(t *testing.T) {
    // Switch to test mode so you don't get such noisy output
    gin.SetMode(gin.TestMode)

    // Setup your router, just like you did in your main function, and
    // register your routes
    r := gin.Default()
    r.POST("/", PostMethod)

    // Create the mock request you'd like to test. Make sure the second argument
    // here is the same as one of the routes you defined in the router setup
    // block!
    req, err := http.NewRequest(http.MethodPost, "/", nil)
    if err != nil {
        t.Fatalf("Couldn't create request: %v\n", err)
    }

    // Create a response recorder so you can inspect the response
    w := httptest.NewRecorder()

    // Perform the request
    r.ServeHTTP(w, req)
    fmt.Println(w.Body)

    // Check to see if the response was what you expected
    if w.Code == http.StatusOK {
        t.Logf("Expected to get status %d is same ast %d\n", http.StatusOK, w.Code)
    } else {
        t.Fatalf("Expected to get status %d but instead got %d\n", http.StatusOK, w.Code)
    }
}

func TestGetMethod(t *testing.T) {
    // Switch to test mode so you don't get such noisy output
    gin.SetMode(gin.TestMode)

    // Setup your router, just like you did in your main function, and
    // register your routes
    r := gin.Default()
    r.GET("/", GetMethod)

    // Create the mock request you'd like to test. Make sure the second argument
    // here is the same as one of the routes you defined in the router setup
    // block!
    req, err := http.NewRequest(http.MethodGet, "/", nil)
    if err != nil {
        t.Fatalf("Couldn't create request: %v\n", err)
    }

    // Create a response recorder so you can inspect the response
    w := httptest.NewRecorder()

    // Perform the request
    r.ServeHTTP(w, req)
    fmt.Println(w.Body)

    // Check to see if the response was what you expected
    if w.Code == http.StatusOK {
        t.Logf("Expected to get status %d is same ast %d\n", http.StatusOK, w.Code)
    } else {
        t.Fatalf("Expected to get status %d but instead got %d\n", http.StatusOK, w.Code)
    }
}
```
- Below command can be used to verify the Unit Testing of REST API, 
```
go test
```


# **REST API RealTime Testing**
- We will now see, how we can test the REST API in real-time.
- I have explained 4 different ways to test the REST API,
  - Ngrok method
  - Test via `curl` command
  - Deploy as docker container
  - Deploy using Google Cloud Kube Clouster

## Ngrok method
- Execute the `go run` command to start the API,
`go run api.go`
- To verify our REST API, we need to expose the localhost of the server to internet
- So we can use "ngrok" for this purpose
- Download [ngrok here](https://dl.equinox.io/ngrok/ngrok/stable) 
- Extract the ngrok executable in some location on your server.
- Start ngrok on port 4000(Port defined in go API code) as below,

`./ngrok http 4000`
- ngrok generates a dynamic URL. For ex: `http://123er5678.ngrok.io`

- The REST API can be tested by adding the URL in browser address bar, 
`http://123er5678.ngrok.io/` 

- The browser should show,
`GetMethod Called`

## Test via Curl
- Otherwise, we can use curl command inside same server to verify the endpoint URL, return success.

- Execute the `go run` command to start the API,
`go run api.go`

- In the same server, in which our REST API is running, execute the below commands, to verify the API

- POST method
`curl -X POST http://localhost:4000/`

- The console output should show,
`PostMethod Called`

- GET method
`curl -X GET http://localhost:4000/`

- The console output should show,
`GetMethod Called`

## Deploy API using docker container
- Create a `Dockerfile` in the `api` directory. Use the file here as reference.
```
FROM golang:latest # Use alpine version if you prefer smaller size

# Set necessary environmet variables needed for our image
ENV GO111MODULE=on \
    CGO_ENABLED=0 \
    GOOS=linux \
    GOARCH=amd64

WORKDIR /root/go/src/api

COPY . .

RUN go get -d -v ./...
RUN go install -v ./...

# Export necessary port
EXPOSE 4000

CMD ["api"]
```
- Then Run following commands to Build and Run the `docker image`
```
docker build -t apigopgm . --rm
docker image ls
docker run -p 4000:4000 --name apicontainer --rm apigopgm
```
- Now the REST API can be accessible from the endpoint URL,
`http://localhost:4000/`

- Now using Curl or Ngrok test method, we can test the API.

- After the testing is completed, we can stop the container.
```
docker container ls
docker stop apicontainer
```

## Deploy using Google Cloud Kubernetes Cluster
### Create API service using Google Cloud Kubernetes Engine
- Login into Google Cloud Console
- Open Navigation menu from the left and choose `Compute > Kubernetes Engine`
- Choose `Clusters > Create Cluster` and follow instructions to create Cluster
- Next, choose `Workloads > Deploy` to create the container workload and attach it to the Cluster created above
- It is possible to create the container by linking the "github" repository
- Choose the appropriate `Dockerfile` to create image, in this repo, Dockerfile located under the path `src/api/`
- The image created as part of this deployment will be stored into `Google Container Registry (GCR)`
- Once the kube deployment is successful, we then have to expose the Service as `API Endpoint` to consume the REST API functions.
- Choose `expose` option and provide the port number, in which the REST API application has been configured in the code.
- In our case, we have exposed the API at `port 4000`
- After exposing the Kube workload, it generates the `publicIP:4000` for us to utilise the API.

Note: Refer the [Google documentation](https://cloud.google.com/source-repositories/docs/mirroring-a-github-repository) for connecting the Github repo with GCP.

## Code Structure
```
./api
|__api.go
|__api_test.go
|__go.mod
|__go.sum
|__Dockerfile
|__README.md

```

## Key Takeaways
We have gone through below topics in this blogs,
- What is REST API
- How to develop simple REST API using golang
- How to unit test the REST API
- Various methods of testing the REST API in realtime

### Bibliography
[REST API](https://restfulapi.net/)
[Go Gin REST API framework](https://github.com/gin-gonic/gin)
```
Thanks for reading! 
If you like the blog, please show some support and re-share.
```