How to Develop REST API using Go and Test using various methods

Saravanan Gnanaguru - Apr 26 '22 - - Dev Community

Table of Contents

Introduction

  • In this blog we will see, the basics of REST API and how to develop REST API using Go.
  • We will also discuss testing the REST API using various methods

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
Enter fullscreen mode Exit fullscreen mode

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 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

Start development

  • Create directory to develop Golang api
cd $GOHOME/src
mkdir api
Enter fullscreen mode Exit fullscreen mode
  • 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

import (
  "fmt"
  "net/http"
  "github.com/gin-gonic/gin"
)
Enter fullscreen mode Exit fullscreen mode

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 "/"
  router.POST("/", PostMethod)
  router.GET("/", GetMethod)
Enter fullscreen mode Exit fullscreen mode
  • Listen to the specified port of localhost
  listenPort := "4000"
  // Listen and Server on the LocalHost:Port
  router.Run(":"+listenPort)
Enter fullscreen mode Exit fullscreen mode

POST and GET methods

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

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)
}
Enter fullscreen mode Exit fullscreen mode

Full Go source for REST API

Please find the source code here

// 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)
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Writing Go Test Program

  • Go provides the built-in functionality to test your Go code. Hence, we don't need an expensive setup or 3rd party libraries to create unit tests.
  • Go has the module called testing to achieve the same.
  • So if we want to test a go program, we can create a unit test file with <source_go_filename>_test.go.
  • For example: We have created api.go source file. So create test file as api_test.go to unit test the api.go functionality.

Go Test Program Structure

  • Go test program also follows the similar statement pattern as main source go file.
  • It should have the below sections,
    • package statement
    • import statement
    • func main()

Go Test Program to Test 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
// 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)
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Below command can be used to verify the Unit Testing of REST API,
go test
Enter fullscreen mode Exit fullscreen mode

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
  • 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"]
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode

Code Structure

./api
|__api.go
|__api_test.go
|__go.mod
|__go.sum
|__Dockerfile
|__README.md

Enter fullscreen mode Exit fullscreen mode

Conclusion

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

  • This article was previously published on my dev community personal profile, re-publishing for the benefit of a wider audience.

  • Hope this article is helpful to people getting started with kubernetes concepts.

Further Reference

REST API
Go Gin REST API framework
Go Source code

Thanks for reading! 
If you like the blog, please show some support and re-share.
Enter fullscreen mode Exit fullscreen mode

Follow me on,

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .