Develop REST API using Go with API versioning, Basic Auth and Query String
Tags: go, beginners, tutorial, restapi
Published: 2022-05-04 11:21:35

## Table of content
- [Introduction](#introduction)
- [Objective](#objective)
- [Source Repo](#source-repo)
- [Function main](#function-main)
  - [Adding API Versioning and Basic authentication](#adding-api-versioning-and-basic-authentication)
  - [Passing Query String Parameters](#passing-query-string-parameters)
  - [REST API Listening on Port](#rest-api-listening-on-port)
- [Get Method](#get-method)
- [Full Source Code](#full-source-code)
- [Go REST API Unit testing](#go-rest-api-unit-testing)
- [Executing Go Unit Testing](#executing-go-unit-testing)
- [Go Source Build and Run](#go-source-build-and-run)
- [Real time test](#real-time-test)
  - [Localhost method](#localhost-method)
  - [Ngrok method](#ngrok-method)
- [Conclusion](#conclusion)

---

## Introduction
We have learnt how to create simple REST API in the [previous blog](https://dev.to/kcdchennai/how-to-develop-rest-api-using-go-and-test-using-various-methods-1j38).
We will see the below topics in this blog,
How to,
- Add REST API versioning
- Create query string parameters
- Add basic authentication to REST API
- Write Go unit testing for API authentication code
- Test the REST API with authentication in real time

---

## Objective
- We will be creating REST API that listens on `localhost` port `1357` and has the API versioning with query string parameter.
- Sample URL format we are planning to create, `http://localhost:1357/api/v1/PersonId/Id432`

## Source Repo
Checkout the full source repo here in [GitHub](https://github.com/chefgs/golang/tree/master/src/apiauth)

Let us start break the code into blocks,

## Function main
Add the below code function `main()`

## Adding API Versioning and Basic authentication
```
  // Define gin router
  router := gin.Default()

  // Create Sub Router for customized API version and basic auth
  subRouterAuthenticated := router.Group("/api/v1/PersonId", gin.BasicAuth(gin.Accounts{
    "basic_auth_user": "userpass",
  }))
```

## Passing Query String Parameters
```
  subRouterAuthenticated.GET("/:IdValue", GetMethod)
```
## REST API Listening on Port
```
  listenPort := "1357"
  // Listen and Server on the LocalHost:Port
  router.Run(":"+listenPort)
```

## Get Method
- Define a `GetMethod` function and add the following code 
- It fetches and prints the `Person IdValue` from the query string parameter passed in the API URL
```
func GetMethod(c *gin.Context) {
  fmt.Println("\n'GetMethod' called")
  IdValue := c.Params.ByName("IdValue")
  message := "GetMethod Called With Param: " + IdValue
  c.JSON(http.StatusOK, message)

  // Print the Request Payload in console
  ReqPayload := make([]byte, 1024)
  ReqPayload, err := c.GetRawData()
  if err != nil {
        fmt.Println(err)
        return
  }
  fmt.Println("Request Payload Data: ", string(ReqPayload))
}
```

---

## Full Source Code
```
// Golang REST API with API versioning and Basic Auth
package main

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

func GetMethod(c *gin.Context) {
  fmt.Println("\n'GetMethod' called")
  IdValue := c.Params.ByName("IdValue")
  message := "GetMethod Called With Param: " + IdValue
  c.JSON(http.StatusOK, message)

  ReqPayload := make([]byte, 1024)
  ReqPayload, err := c.GetRawData()
  if err != nil {
        fmt.Println(err)
        return
  }
  fmt.Println("Request Payload Data: ", string(ReqPayload))
}

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

  // Create Sub Router for  customised API version
  subRouterAuthenticated := router.Group("/api/v1/PersonId", gin.BasicAuth(gin.Accounts{
    "admin": "adminpass",
  }))

  subRouterAuthenticated.GET("/:IdValue", GetMethod)

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

## Go REST API Unit testing
- Go `testing` module can be used for creating unit testing code for Go source

- Go Unit testing code looks as below,

```
// Golang REST API unit testing program
package main

import (
  "testing"
  "net/http"
  "net/http/httptest"
  "fmt"
  "bytes"

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

    // 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!
    body := bytes.NewBuffer([]byte("{\"ApiTest\":\"GetReq\"}"))
    req, err := http.NewRequest("GET", "/api/v1/PersonId/Id456", body)
    if err != nil {
        t.Fatalf("Couldn't create request: %v\n", err)
    }
    req.Header.Set("Content-Type", "application/json")
    req.SetBasicAuth("admin", "adminpass")

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

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

    // Perform the request
    router.ServeHTTP(w, req)
    fmt.Println(w.Body)
}
```
- Refer my [previous blog section](https://dev.to/kcdchennai/how-to-develop-rest-api-using-go-and-test-using-various-methods-1j38#writing-go-test-program) `Write go test program` to know more about writing go test code

---

## Executing Go Unit Testing
Run the command `go test` and it shows the below output in console,
```
'GetMethod' called
Request Payload Data:  {"ApiTest":"GetReq"}
[GIN] 2020/08/03 - 12:26:29 | 200 |         7.2µs |                 | GET      "/api/v1/PersonId/Id456"
"GetMethod Called With Param: Id456"
PASS
ok  	apiauth	0.008s
```
This confirms the REST API code we have created is working fine.

## Go Source Build and Run
- If we want to test the API in our server, on which the code is created, run the below command
```
go run apiauth.go
```
- This command invokes the REST API on `localhost` port `1357` & console shows the below output,
```
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /api/v1/PersonId/:IdValue --> main.GetMethod (4 handlers)
[GIN-debug] Listening and serving HTTP on :1357
```

- Then proceed to test the REST API real-time

---

## Real time test 
### Localhost method
Run `curl` with basic authentication user-password
```
curl -u admin:adminpass -i -X GET http://localhost:1357/api/v1/PersonId/Id456
```
- This will show the output as below in Console
```
"GetMethod Called With Param: Id456"
```
- In Ubuntu, Access the `localhost` URL in browser and enter the basic auth username and password when prompted
- After entering the credential, the browser should show,
`GetMethod Called With Param: Id456`

### Ngrok method
- Execute the `go run` command to start the API,
`go run apiauth.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 1357(Port defined in go API code) as below,

`./ngrok http 1357` and prints the output as follows in console
```
ngrok by @inconshreveable                                                    (Ctrl+C to quit)
                                                                                             
Session Status                online                                                         
Session Expires               7 hours, 12 minutes                                            
Version                       2.3.35                                                         
Region                        United States (us)                                             
Web Interface                 http://127.0.0.1:4040                                          
Forwarding                    http://ca6d2c4cee3e.ngrok.io -> http://localhost:4000          
Forwarding                    https://ca6d2c4cee3e.ngrok.io -> http://localhost:4000         
```
- ngrok generates a dynamic URL. For ex: `http://ca6d2c4cee3e.ngrok.io`

- The REST API can be tested by adding the URL in browser address bar, 
`http://ca6d2c4cee3e.ngrok.io/api/v1/PersonId/Id456`

- Browser will prompt to enter the authentication details. So enter credentials
![Image of Authprompt](https://github.com/chefgs/repo_images/blob/master/authprompt.jpg?raw=true)

- After entering the credential, the browser should show,
`GetMethod Called With Param: Id456`
![Image of Output](https://github.com/chefgs/repo_images/blob/master/output.jpg?raw=true)

## Conclusion
We have seen the below topics in this blog,
- Adding basic authentication to REST API
- Go unit testing for API authentication code
- Testing the REST API with basic authentication in real time

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

### Follow me on,
- [GitHub](https://github.com/chefgs)
- [LinkedIn](https://www.linkedin.com/in/saravanan-gnanaguru-1941a919/)
- [Twitter](https://twitter.com/saransid)
- [gsaravanan.dev](https://gsaravanan.dev)