Membuat CRUD Rest API di Golang menggunakan GORM dan Mux : Edisi Pemula

Saya baru-baru ini mempelajari bahasa pemrograman Go khususnya dalam kasus pengembangan aplikasi web. Tidak perlu ditanyakan sebabnya, karena sebagai orang yang terjun di dunia teknologi, pasti harus selalu memperbarui ilmu setiap saat agar tidak tertinggal dengan yang lain, begitu juga saya. Prinsip belajar saya adalah mencoba dan mengulang kembali agar tidak lupa. Oleh karena itu, dalam waktu kedepan, akan banyak tulisan saya mengenai penerapan bahasa Go dalam berbagai kasus sederhana. Selain bisa untuk belajar saya pribadi, juga bisa dibaca oleh siapa saja yang berkunjung ke web ini.

Dalam artikel ini, kita akan belajar bagaimana membuat CRUD REST API menggunakan bahasa Go. Saya tidak memakai full framework seperti GIN , Echo atau Fiber, akan tetapi saya coba menggunakan libary Gorilla Mux untuk routing dan GORM untuk pengaksesan database. Untuk manajemen konfigurasi saya menggunakan Viper, dan database menggunakan MySQL. Saya akan coba pendekatan yang menurut saya paling mudah dipahami oleh pemula seperti saya, termasuk pembuatan struktur direktori dalam aplikasi ini.

Read more

Setup Project

Dengan menggunakan terminal / konsole saya membuat direktori untuk project ini sebagai berikut

mkdir golang-crud-api
cd golang-crud-api

Setelah masuk kedalam direktori project, buat go.mod dengan perintah sebagai berikut

go mod init go-crud-api

Lakukan instalasi pada library yang dibutuhkan, perintahnya adalah sebagai berikut (jalankan satu persatu, tunggu hingga selesai)

go get -u github.com/gorilla/mux
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
go get -u github.com/spf13/viper

Penjelasan dari perintah di atas adalah

  • Gorilla/Mux digunakan untuk mengatur routing dari aplikasi nantinya. Misalnya GET /users akan diarahkan ke fungsi getUser, POST /user akan diarahkan ke fungsi postUser dan sebagainya.
  • Gorm adalah sebuah ORM untuk mempermudah manajemen query ke dalam database. Alih-alih menuliskan script SQL, dengan GORM dapat diubah menjadi fungsi yang lebih mudah dipahami.
  • Driver Mysql, karena kita menggunakan database MySQL maka diperlukan libray ini
  • viper digunakan untuk manajemen konfigurasi yang membantu kita memuat file dan nilai yang akan digunakan dalam aplikasi

Buat main.go dan buka dengan editor kalian

touch main.go
code . //untuk membuka dengan visual studio code
vim . //untuk membuka dengan vim editor
nvim . //untuk membuka dengan neovim editor

dan buat function main seperti berikut

package main

func main() {

}

Mengatur konfigurasi dengan Viper

Buat file dengan nama config.go Isikan dengan kode berikut

package main
import (
	"log"
	"github.com/spf13/viper"
)
type Config struct {
	Port             string `mapstructure:"port"`
	ConnectionString string `mapstructure:"connection_string"`
}
var AppConfig *Config
func LoadAppConfig() {
	log.Println("Loading server configuration")
	viper.AddConfigPath(".")
	viper.SetConfigName("config")
	viper.SetConfigType("json")
	err := viper.ReadInConfig()
	if err != nil {
		log.Println(err)
	}
	err = viper.Unmarshal(&AppConfig)
	if err != nil {
		log.Println(err)
	}
}

Kita analisa bersama, dimulai dari baris 9-12 adalah untuk mendefiniskan struct yang nantinya akan digunakan dalam konfigurasi aplikasi. Saat ini kita atur isinya dengan port aplikasi dan koneksi database yang akan digunakan.

Baris 14 digunakan untuk membuat variabel dengan type data struct Config

Baris 16-30 adalah fungsi dimana tempat Viper akan memuat konfigurasi dari config.json. Nantinya fungsi ini dipanggil di main program untuk menerapkan konfigurasinya.

Selanjutnya buat file config.json dan isi sebagai berikut

{
    "connection_string": "root:[email protected](127.0.0.1:3306)/go_crud_api",
    "port": 8080
}

Model Entity

Sekarang saatnya membuat model, layaknya di platform / frameworks lain, models digunakan untuk mockuop data dari table di database. Buat sebuah folder dengan nama entities dan buat file dengan nama product.go sebagai entitas model untuk table products yang akan kita buat nanti. Isi file product.go adalah sebagai berikut,

package entities
type Product struct {
	ID         uint    `json:"id"`
	Name       string  `json:"name"`
	Price      float64 `json:"price"`
	Dscription string  `json:"description"`
}

Penjelasan sederhananya adalah, struct product berisikan atribut table product dan format datanya serta format jsonnya.

Menghubungkan dengan database

Langkah berikut adalah membuat koneksi dengan database. Oleh karena itu buat folder dengan nama database dan buat file dengan nama client.go isi dengan code berikut

package database
import (
	"go-crud-api/entities"
	"log"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)
var Instance *gorm.DB
var err error
func Connect(ConnectionString string) {
	Instance, err = gorm.Open(mysql.Open(ConnectionString), &gorm.Config{})
	if err != nil {
		log.Fatal(err)
		panic("Cannot connect to database")
	}
	log.Println("Connecting to database")
}
func Migrate() {
	Instance.AutoMigrate(&entities.Product{})
	log.Println("Database migration completed")
}

Baris 11-12 adalah membuat instansiasi variable DB dan variable error

Baris 14-21 adalah fungsi untuk menghubungkan ke database, disertakan error handling jika koneksi tidak berhasil

Baris 23-25 adalah fungsi untuk membuat migrasi sesuai entitas yang sudah dibuat.

Mulai membuat routing

Seperti disebutkan sebelumnya, kita akan menggunakan MUX untuk penanganan routing pada aplikasi ini. Untuk itu, buka kembali file main.go dan tambahkan fungsi berikut

func ProductHandlers(router *mux.Router) {
	router.HandleFunc("/api/products", controllers.GetProducts).Methods(http.MethodGet)
	router.HandleFunc("/api/products/{id}", controllers.GetProductById).Methods(http.MethodGet)
	router.HandleFunc("/api/products", controllers.CreateProduct).Methods(http.MethodPost)
	router.HandleFunc("/api/products/{id}", controllers.UpdateProduct).Methods(http.MethodPut)
	router.HandleFunc("/api/products/{id}", controllers.DeleteProduct).Methods(http.MethodDelete)
}

Perhatikan format perintah dalam fungsi tersebut, jika kita sudah terbiasa menggunakan framework web lain, akan tampak familiar dengan kode diatas, terutama bagian parameter pada method HandleFunc. Parameter pertama adalah path, parameter selanjutnya adalah function. Jadi sederhanya adalah path “/api/products” akan diproses pada fungsi GetProducts. Sedangkan bagian terakhir adalah Methods menunjukan methoh HTTP yang digunakan untuk memanggil path tersebut, ada GET,POST,PUT dan DELETE

Saat ini akan muncul error karena package controllers belum dibuat.

Membuat Controller

File controllers akan kita letakkan di folder controllers, oleh karena itu buat terlebih dahulu folder controllers, dan buat file product_controller.go di dalamnya. Sekarang seluruh struktur direktori dan file pada aplikasi sudah selesai dibuat semua, dengan gambaran seperti berikut

struktur direktori aplikasi

Get Products

Fungsi ini digunakan dalam path /products (perhatikan fungsi router pada main.go) Isinya adalah mendapatkan keseluruhan data dari table di database. Isinya sebagai berikut

func GetProducts(w http.ResponseWriter, r *http.Request) {
	var products []entities.Product
	database.Instance.Find(&products)
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(products)
}

Get Product By Id

Fungsi ini digunakan dalam path /product/{id}. Isinya adalah mendapatkan data sesuai ID dari url. Isinya sebagai berikut

func GetProductById(w http.ResponseWriter, r *http.Request) {
	productID := mux.Vars(r)["id"]
	var product entities.Product
	w.Header().Set("Content-Type", "application/json")
	database.Instance.First(&product, productID)
	if product.ID == 0 {
		json.NewEncoder(w).Encode("Product not found")
	} else {
		json.NewEncoder(w).Encode(product)
	}
}

Create Product

Fungsi ini digunakan dalam path Post /product. Berfungsi untuk menyimpan data dari request ke dalam table

func CreateProduct(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	var product entities.Product
	json.NewDecoder(r.Body).Decode(&product)
	database.Instance.Create(&product)
	json.NewEncoder(w).Encode(product)
}

Update Product By Id

Fungsi ini dipanggil dalam path PUT /product/{id}. Digunakan untuk mengupdate product dengan ID sesuai parameter yang ditentukan

func UpdateProduct(w http.ResponseWriter, r *http.Request) {
	productID := mux.Vars(r)["id"]
	var product entities.Product
	w.Header().Set("Content-Type", "application/json")
	database.Instance.First(&product, productID)
	if product.ID == 0 {
		json.NewEncoder(w).Encode("Product not found")
	} else {
		json.NewDecoder(r.Body).Decode(&product)
		database.Instance.Save(&product)
		json.NewEncoder(w).Encode(product)
	}
}

Delete Product By Id

Fungsi ini dipanggil dalam path DELETE /product/{id}. Digunakan untuk menghapus product dengan ID sesuai parameter yang ditentukan

func DeleteProduct(w http.ResponseWriter, r *http.Request) {
	productID := mux.Vars(r)["id"]
	var product entities.Product
	w.Header().Set("Content-Type", "application/json")
	database.Instance.First(&product, productID)
	if product.ID == 0 {
		json.NewEncoder(w).Encode("Product not found")
	} else {
		json.NewDecoder(r.Body).Decode(&product)
		database.Instance.Delete(&product, productID)
		json.NewEncoder(w).Encode("Product deleted")
	}
}

Wrap Up the code

Saatnya menghubungkan semua fungsi yang sudah dibuat di fungsi main. Buka main.go dan ubah pada fungsi main menjadi sebagai berikut

func main() {
	LoadAppConfig()

	database.Connect(AppConfig.ConnectionString)
	database.Migrate()

	router := mux.NewRouter().StrictSlash(true)
	ProductHandlers(router)

	log.Println(fmt.Sprintf("starting server on port %s", AppConfig.Port))
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", AppConfig.Port), router))
}

Uji Coba

jalankan program dengan perintah

go run *.go

Lakukan request ke server dengan Postman atau CURL sesuai dengan path yang sudah ditentukan. Misalkan untuk path /products seperti berikut

curl -X GET  'http://localhost:8080/api/products'

Untuk membuat product dengan method POST, gunakan kode berikut

curl -X POST \
  'http://localhost:8080/api/products' \
  --header 'Content-Type: application/json' \
  --data-raw '{
  "name":"New Barang ",
  "price":20000,
  "description":"Barang pribadi yang sering digunakan"
}'

Mengambil product dengan Id tertentu

curl -X GET 'http://localhost:8080/api/products/2'

Mengupdate product

curl -X PUT \
  'http://localhost:8080/api/products/3' \
  --data-raw '{
  "name":"New Barang Update "
}'

Menghapus product

curl -X DELETE 'http://localhost:8080/api/products/2'

Seluruh file kode sudah saya upload di https://github.com/dwijonarko/go-crud-api. Semoga bermanfaat

1 thought on “Membuat CRUD Rest API di Golang menggunakan GORM dan Mux : Edisi Pemula

  1. Pingback: Membuat REST API dengan Golang Framework Echo | dudu.WEB.ID

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.