Create Sample Rest API & Unit Test in Golang

Unit test merupakan fungsi/potongan kode yang melakukan testing pada potongan kode atau program. Tugas dari unit test adalah untuk memastikan kebenaran fungsi berjalan dengan baik. Pada tulisan ini akan memandu Anda untuk membuat sample Rest API dengan Go dan melakukan testing pada fungsi yang telah dibangun.

Prerequisites

Pastikan Anda telah melakukan instalasi Go sebelumnya dan sudah berjalan dengan baik dan akan lebih baik jika Anda telah mengikuti tutorial ini sebelumnya.

1. Create Rest API Sederhana untuk Unit Test

Sebelum melakukan test dengan unit test yang nantinya dibangun, mari kita buat program sederhana dulu Rest API berkaitan dengan Get, Insert, Get by ID article.

go mod init blog

Create file untuk main program dengan function Get List, Insert dan Get by ID data article dari sebuah array Article

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

type article struct {
	Id          string `json:"ID"`
	Title       string `json:"Title"`
	Description string `json:"Description"`
}

type allArticle []article

var articles = allArticle{
	{
		Id:          "1",
		Title:       "Top 10 Tools For StartUp 2022",
		Description: "Just sample description",
	},
}

/**
* Function to insert new data to articles
 */
func insert(w http.ResponseWriter, r *http.Request) {
	var newArticle article
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintf(w, "Formulir Data kosong")
	}

	json.Unmarshal(reqBody, &newArticle)
	articles = append(articles, newArticle)
	// send http status
	w.WriteHeader(http.StatusCreated)
	// return json new article
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(newArticle)

}

/**
Read Params in route
*/
func getArticle(w http.ResponseWriter, r *http.Request) {
	articleId := mux.Vars(r)["id"]
	for _, singleArticle := range articles {
		if singleArticle.Id == articleId {
			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(singleArticle)
		}
	}

}
func displayData(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(articles)
}

func main() {
	router := mux.NewRouter().StrictSlash(true)
	router.HandleFunc("/articles", displayData).Methods("GET")
	router.HandleFunc("/articles", insert).Methods("POST")
	router.HandleFunc("/articles/{id}", getArticle).Methods("GET")
	log.Fatal(http.ListenAndServe(":8080", router))
}

Keterangan package yang digunakan pada program ini diantaranya:
Encoding/json untuk melakukan parse (encode,decode) Json – Object
io/ioutil untuk melakukan fungsi-fungsi yang berhubungan dengan I/O seperti ReadAll pada program diatas.
net/http adalah package http untuk implementasi HTTP Client & Server
Gorilla/Mux adalah pacakge untuk implementasi router dan memetakan request dan http handler

2. Preparation & Define Struct

Pada Golang tidak dikenal dengan Class namun dengan Struct (Type Data), jika Anda pernah program dengan C/C++ pastinya struct ini tidaklah hal yang baru buat Anda. Ambil contoh sebuah type data article dengan field ( ID, Title & Description )

type article struct {
	Id          string `json:"ID"`
	Title       string `json:"Title"`
	Description string `json:"Description"`
}

Kemudian create sebuah tipe baru yang merupakan tipe data array of article dan sebuah variable articles dengan tipe data allArticle yang akan digunakan sebagai penyimpan data article untuk insert.

//declare new type
type allArticle []article
//declare and initialize value
var articles = allArticle{
	{
		Id:          "1",
		Title:       "Top 10 Tools For StartUp 2022",
		Description: "Just sample description",
	},
}

3. Create Function Display, Insert & Get By ID

Selanjutnya create function untuk menampilkan semua artikel dari variable array article yang sudah di init sebelumya. DisplayData

func displayData(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(articles)
}

Set header http response (writer) dalam bentuk json dan return array of articles dalam bentuk json.

InsertData

func insert(w http.ResponseWriter, r *http.Request) {
	var newArticle article
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintf(w, "Formulir Data kosong")
	}

	json.Unmarshal(reqBody, &newArticle)
	articles = append(articles, newArticle)
	// send http status
	w.WriteHeader(http.StatusCreated)
	// return json new article
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(newArticle)

}

ioutil.ReadAll adalah fungsi untuk melakukan membaca /get data body http request. Kemudian melakukan parse requestbody kedalam bentuk Article dengan function unmarshall.

Selanjutnya adalah dengan append data ke record baru pada array of articles dan return new data dalam bentuk json (writer)

GetDataByID

func getArticle(w http.ResponseWriter, r *http.Request) {
	articleId := mux.Vars(r)["id"]
	for _, singleArticle := range articles {
		if singleArticle.Id == articleId {
			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(singleArticle)
		}
	}

}

Lakukan pencarian data article yang sesuai dengan param request dan kemudian return json element yang ditemukan. “id” adalah params name yang akan di define pada router

4. Create Main Program

func main() {
	router := mux.NewRouter().StrictSlash(true)
	router.HandleFunc("/articles", displayData).Methods("GET")
	router.HandleFunc("/articles", insert).Methods("POST")
	router.HandleFunc("/articles/{id}", getArticle).Methods("GET")
	log.Fatal(http.ListenAndServe(":8080", router))
}

Define router dari package mux dan daftarkan satu persatu router REST API yang dibangun lengkap dengan HTTP Method yang diijinkan.

5. Run Main Program & Test Postman

Run main program dengan command berikut go run . dan buka postman dan test masing-masing endpointya.

Get List of Article

Insert Article

Get Article by ID

6. Create Unit Test File

Selanjutnya adalah menuliskan unit test dan melakukan test pada fungsi yang telah dibuat sebelumnya, pada tutorial ini kita berikan sample unit test untuk display data dan insert data.

package main

import (
	"bytes"
	"github.com/gorilla/mux"
	"github.com/stretchr/testify/assert"
	"net/http"
	"net/http/httptest"
	"testing"
)

func Router() *mux.Router {
	router := mux.NewRouter()
	router.HandleFunc("/articles", displayData).Methods("GET")
	router.HandleFunc("/articles", insert).Methods("POST")
	router.HandleFunc("/articles/{id}", getArticle).Methods("GET")
	return router
}

func TestDisplayArticles(t *testing.T) {
	request, _ := http.NewRequest("GET", "/articles", nil)
	response := httptest.NewRecorder()
	Router().ServeHTTP(response, request)
	assert.Equal(t, 200, response.Code, "OK response is expected")
}
func TestInsertArticle(t *testing.T) {
	testBody := `{"ID": "100", "Title": "Judul","Description": "Deskripsi"}`
	request, _ := http.NewRequest("POST", "/articles", bytes.NewBufferString(testBody))
	response := httptest.NewRecorder()
	Router().ServeHTTP(response, request)
	assert.Equal(t, 201, response.Code, "OK response is expected")
}

Import package yang diperlukan dan daftarkan router dari endpoint yang akan di test seperti list dan insert.

Pada testing ini kita menggunakan package testify untuk simplifikasi test expected result.

Jalankan test dengan command go test -v atau dengan command berikut untuk melihat coverage code go test -coverprofile=coverage.out

Tagged with: