Belajar Golang #44 : Membuat REST API + MySQL – Delete Data

Tutorial Golang ke-44 yaitu membuat REST API dengan Golang menggunakan Database MySQL dimana tutorial ini akan melakukan delete data dalam bentuk data json.

Tutorial CRUD API golang untuk aksi hapus kali ini lanjutan dari tutorial :

Membuat REST API + MySQL – Delete Data

Delete data api dengan Golang dan MySQL merupakan seri terakhir dari belajar membuat CRUD API dengan golang dan MySQL.

Apa saja yang ingin kita lakukan ?

  • Membuat Routing untuk Delete.
  • Membuat Method Delete.
  • Membuat Query Delete Ke database MySQL.

Langsung saja mari kita buat kode nya satu persatu.

Membuat Routing dan Method

Untuk membuat routing dan method kita menggunakan file main.go. Dimana untuk routingnya sendiri terdapat pada fungsi main. Sedangkan untuk method baru nya yaitu DeleteMahasiswa().

Berikut ini kode routing untuk aksi delete.

http.HandleFunc("/mahasiswa/delete", DeleteMahasisw)

Dan kode lengkap pada fungsi main() adalah

func main() {

	http.HandleFunc("/mahasiswa", GetMahasiswa)
	http.HandleFunc("/mahasiswa/create", PostMahasiswa)
	http.HandleFunc("/mahasiswa/update", UpdateMahasiswa)
	http.HandleFunc("/mahasiswa/delete", DeleteMahasiswa)

	err := http.ListenAndServe(":7000", nil)

	if err != nil {
		log.Fatal(err)
	}
}

Jika sudah saat nya membuat fungsi atau method baru dengan nama DeleteMahasiswa

Berikut ini kode nya :

// DeleteMahasisw
func DeleteMahasiswa(w http.ResponseWriter, r *http.Request) {

	if r.Method == "DELETE" {

		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		var mhs models.Mahasiswa

		id := r.URL.Query().Get("id")

		if id == "" {
			utils.ResponseJSON(w, "id tidak boleh kosong", http.StatusBadRequest)
			return
		}
		mhs.ID, _ = strconv.Atoi(id)

		if err := mahasiswa.Delete(ctx, mhs); err != nil {

			kesalahan := map[string]string{
				"error": fmt.Sprintf("%v", err),
			}

			utils.ResponseJSON(w, kesalahan, http.StatusInternalServerError)
			return
		}

		res := map[string]string{
			"status": "Succesfully",
		}

		utils.ResponseJSON(w, res, http.StatusOK)
		return
	}

	http.Error(w, "Tidak di ijinkan", http.StatusMethodNotAllowed)
	return
}

Perhatikan kode di atas, kita menggunakan standart method routing dimana untuk melakukan delete data maka kita harus menggunakan method DELETE.

Untuk menghapus data MySQL kita membutuhkan parameter id sebagai kunci penghapusan, bahasa umumnya yaitu primary key(PK).

Untuk mengambil id dengan model url ?id=blabla dengan menggunakan kode r.URL.Query().Get("id").

Secara default, nilai balik dari kode di atas string, maka dari itu kita harus mengubah nya ke dalam bentuk integer agar sesuai dengan struct Mahasiswa di tandai dengan kode strconv.Atoi(id).

Selanjutnya jika sudah berhasil mengambil id dari parameter maka akan di panggil fungsi Delete yang ada di mahasiswa/repository_mysql. Asumsikan dulu kita udah punya.

Sehingga di file main.go kode lengkapnya seperti di bawah ini.

main.go

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/kodingin/api-mysql/mahasiswa"
	"github.com/kodingin/api-mysql/models"
	"github.com/kodingin/api-mysql/utils"
	"log"
	"net/http"
	"strconv"
)

func main() {

	http.HandleFunc("/mahasiswa", GetMahasiswa)
	http.HandleFunc("/mahasiswa/create", PostMahasiswa)
	http.HandleFunc("/mahasiswa/update", UpdateMahasiswa)
	http.HandleFunc("/mahasiswa/delete", DeleteMahasiswa)

	err := http.ListenAndServe(":7000", nil)

	if err != nil {
		log.Fatal(err)
	}
}

// GetMahasiswa
func GetMahasiswa(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		ctx, cancel := context.WithCancel(context.Background())

		defer cancel()

		mahasiswas, err := mahasiswa.GetAll(ctx)

		if err != nil {
			kesalahan := map[string]string{
				"error": fmt.Sprintf("%v", err),
			}

			utils.ResponseJSON(w, kesalahan, http.StatusInternalServerError)
			return
		}

		utils.ResponseJSON(w, mahasiswas, http.StatusOK)
		return
	}

	http.Error(w, "Tidak di ijinkan", http.StatusMethodNotAllowed)
	return
}

// PostMahasiswa
func PostMahasiswa(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {

		if r.Header.Get("Content-Type") != "application/json" {
			http.Error(w, "Gunakan content type application / json", http.StatusBadRequest)
			return
		}

		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		var mhs models.Mahasiswa

		if err := json.NewDecoder(r.Body).Decode(&mhs); err != nil {
			utils.ResponseJSON(w, err, http.StatusBadRequest)
			return
		}

		if err := mahasiswa.Insert(ctx, mhs); err != nil {
			utils.ResponseJSON(w, err, http.StatusInternalServerError)
			return
		}

		res := map[string]string{
			"status": "Succesfully",
		}

		utils.ResponseJSON(w, res, http.StatusCreated)
		return
	}

	http.Error(w, "Tidak di ijinkan", http.StatusMethodNotAllowed)
	return
}

// UpdateMahasiswa
func UpdateMahasiswa(w http.ResponseWriter, r *http.Request) {
	if r.Method == "PUT" {

		if r.Header.Get("Content-Type") != "application/json" {
			http.Error(w, "Gunakan content type application / json", http.StatusBadRequest)
			return
		}

		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		var mhs models.Mahasiswa

		if err := json.NewDecoder(r.Body).Decode(&mhs); err != nil {
			utils.ResponseJSON(w, err, http.StatusBadRequest)
			return
		}

		if err := mahasiswa.Update(ctx, mhs); err != nil {
			kesalahan := map[string]string{
				"error": fmt.Sprintf("%v", err),
			}

			utils.ResponseJSON(w, kesalahan, http.StatusInternalServerError)
			return
		}

		res := map[string]string{
			"status": "Succesfully",
		}

		utils.ResponseJSON(w, res, http.StatusCreated)
		return
	}

	http.Error(w, "Tidak di ijinkan", http.StatusMethodNotAllowed)
	return
}

// DeleteMahasisw
func DeleteMahasiswa(w http.ResponseWriter, r *http.Request) {

	if r.Method == "DELETE" {

		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		var mhs models.Mahasiswa

		id := r.URL.Query().Get("id")

		if id == "" {
			utils.ResponseJSON(w, "id tidak boleh kosong", http.StatusBadRequest)
			return
		}
		mhs.ID, _ = strconv.Atoi(id)

		if err := mahasiswa.Delete(ctx, mhs); err != nil {

			kesalahan := map[string]string{
				"error": fmt.Sprintf("%v", err),
			}

			utils.ResponseJSON(w, kesalahan, http.StatusInternalServerError)
			return
		}

		res := map[string]string{
			"status": "Succesfully",
		}

		utils.ResponseJSON(w, res, http.StatusOK)
		return
	}

	http.Error(w, "Tidak di ijinkan", http.StatusMethodNotAllowed)
	return
}

Sekarang mari kita buat fungsi Delete di file `mahasiswa/repository_mysql.go`.

Query Delete Data Database MySQL dengan Golang

Kita akan buat fungsi dengan nama Delete di file mahasiswa/repository_mysql.go.

Berikut ini kodenya :

mahasiswa/repository_mysql.go

// Delete
func Delete(ctx context.Context, mhs models.Mahasiswa) error {

	db, err := config.MySQL()

	if err != nil {
		log.Fatal("Can't connect to MySQL", err)
	}

	queryText := fmt.Sprintf("DELETE FROM %v where id = '%d'", table, mhs.ID)

	s, err := db.ExecContext(ctx, queryText)

	if err != nil && err != sql.ErrNoRows {
		return err
	}

	check, err := s.RowsAffected()
	fmt.Println(check)
	if check == 0 {
		return errors.New("id tidak ada")
	}

	return nil
}

Perhatikan kode di atas, untuk melakukan delete data kita menggunakan query DELETE dengan parameter Primary Key, dalam contoh di atas adalah id.

Query MySQL delete berada pada isi variable queryText dan di eksekusi dengan perintah exec.

Lalu ketika ada error maka akan mengambalikan nilai error.

Atau apabila id yang di masukkan tidak ada maka akan membuat custom error sendiri di tandai dengan kode return errors.New("id tidak ada ").

Oh iya, pada kode di atas terdapat kode RowsAffected. Kode tersebut untuk mengambil nilai dari apa yang sudah kita hapus.

Sehingga kode lengkapnya berikut ini :

mahasiswa/repository_mysql.go

package mahasiswa

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"github.com/kodingin/api-mysql/config"
	"github.com/kodingin/api-mysql/models"
	"log"
	"time"
)

const (
	table          = "mahasiswa"
	layoutDateTime = "2006-01-02 15:04:05"
)

// GetAll
func GetAll(ctx context.Context) ([]models.Mahasiswa, error) {

	var mahasiswas []models.Mahasiswa

	db, err := config.MySQL()

	if err != nil {
		log.Fatal("Cant connect to MySQL", err)
	}

	queryText := fmt.Sprintf("SELECT * FROM %v Order By id DESC", table)

	rowQuery, err := db.QueryContext(ctx, queryText)

	if err != nil {
		log.Fatal(err)
	}

	for rowQuery.Next() {
		var mahasiswa models.Mahasiswa
		var createdAt, updatedAt string

		if err = rowQuery.Scan(
			&mahasiswa.ID,
			&mahasiswa.NIM,
			&mahasiswa.Name,
			&mahasiswa.Semester,
			&createdAt,
			&updatedAt); err != nil && sql.ErrNoRows != nil {
			return nil, err
		}

		//  Change format string to datetime for created_at and updated_at
		mahasiswa.CreatedAt, err = time.Parse(layoutDateTime, createdAt)

		if err != nil {
			log.Fatal(err)
		}

		mahasiswa.UpdatedAt, err = time.Parse(layoutDateTime, updatedAt)

		if err != nil {
			log.Fatal(err)
		}

		mahasiswas = append(mahasiswas, mahasiswa)
	}

	return mahasiswas, nil
}

// Insert
func Insert(ctx context.Context, mhs models.Mahasiswa) error {

	db, err := config.MySQL()

	if err != nil {
		log.Fatal("Can't connect to MySQL", err)
	}

	queryText := fmt.Sprintf("INSERT INTO %v (nim, name, semester, created_at, updated_at) values(%v,'%v',%v,'%v','%v')",
		table,
		mhs.NIM,
		mhs.Name,
		mhs.Semester,
		time.Now().Format(layoutDateTime),
		time.Now().Format(layoutDateTime))

	_, err = db.ExecContext(ctx, queryText)

	if err != nil && err != sql.ErrNoRows {
		return err
	}

	return nil
}

// Update
func Update(ctx context.Context, mhs models.Mahasiswa) error {

	db, err := config.MySQL()

	if err != nil {
		log.Fatal("Can't connect to MySQL", err)
	}

	queryText := fmt.Sprintf("UPDATE %v set nim = %d, name ='%s', semester = %d, updated_at = '%v' where id = '%d'",
		table,
		mhs.NIM,
		mhs.Name,
		mhs.Semester,
		time.Now().Format(layoutDateTime),
		mhs.ID,
	)
	fmt.Println(queryText)

	_, err = db.ExecContext(ctx, queryText)

	if err != nil && err != sql.ErrNoRows {
		return err
	}

	return nil
}

// Delete
func Delete(ctx context.Context, mhs models.Mahasiswa) error {

	db, err := config.MySQL()

	if err != nil {
		log.Fatal("Can't connect to MySQL", err)
	}

	queryText := fmt.Sprintf("DELETE FROM %v where id = '%d'", table, mhs.ID)

	s, err := db.ExecContext(ctx, queryText)

	if err != nil && err != sql.ErrNoRows {
		return err
	}

	check, err := s.RowsAffected()
	fmt.Println(check)
	if check == 0 {
		return errors.New("id tidak ada ")
	}

	return nil
}

Uji Coba Delete data REST API dengan Golang + MySQL

Jika sudah semua, saatnya kita melakukan uji coba.

Sebelumnya silahkan pilih terlebih dahulu id yang mau di hapus.

Sebagai contoh saya akan menghapus id dengan nilai 5 dengan data berikut ini.

    {
        "id": 5,
        "nim": 456,
        "Name": "Dika",
        "semester": 9,
        "created_at": "2020-03-16T23:16:26Z",
        "updated_at": "2020-03-16T23:16:26Z"
    },

Sekarang saya akan hapus dengan end point http://localhost:7000/mahasiswa/delete?id=5.

Dan lihat hasilnya.

Belajar Golang #44 : Membuat REST API + MySQL – Delete Data
Cara Hapus data API dengan Golang daari database MySQL.

Apabila respon nya yaitu kode status 200 dan terdapat response json seperti gambar di atas maka kita sudah berhasil melakukan delete data api dengan Go dan MySQL.

Agar lebih yakin, silahkan lihat di database anda apakah data benar hilang atau tidak.

Anda bisa mendapatkan kode lengkap nya di

https://github.com/kodingindotkom/golang-api-mysql

Oke sekian tutorial cara hapus data api dengan Golang dari database MySQL. Terima kasih.

3 Comments

  1. Permisi , Apakah saya boleh translate konten agan dan saya post di website saya…

  2. wahh makasih gan mantap emang kenapa gak pakai orm dan framework langsung supaya lebih bisa di maintain lebih gampang 🙂

Leave a Reply