pemrograman

06 Membuat Usecase Sebagai Data Logic

Pada kali ini kita akan melanjutkan projek pembuatan RESTFul API ini dengan membuat fungsi Usecase. Sebelumnya pernah dibahas bahwa Usecase Layer ini akan berisikan data logic atau pengolahan data yang mana digunakan beberapa logic yang dibutuhkan dalam sebuah proses.

Misalkan, usecase pengubah data article ke dalam data yang terbaru dari request user. Maka pada layer usecase ini kita akan membuat logika proses seperti: a. Pengecekan request article_id tidak kosong b. Pengecekan article_id tersebut pada database sudah tersedia c. Proses perubahan data yang diminta user d. Proses handling jika terjadi error pada database

Minimal proses diatas akan diimplementasikan di salah satu fungsi pada usecase layer.

Pembuatan Usecase Interface

Pertama, kita perlu membuat nama file usecase.go pada folder usecase lalu isi file tersebut seperti ini.

package usecase

import (
	"context"

	"github.com/santekno/learn-golang-restful/models"
)

type ArticleUsecase interface {
	GetAll(ctx context.Context) ([]models.ArticleResponse, error)
	GetByID(ctx context.Context, id int64) (models.ArticleResponse, error)
	Update(ctx context.Context, article models.ArticleUpdateRequest) (models.ArticleResponse, error)
	Store(ctx context.Context, article models.ArticleCreateRequest) (models.ArticleResponse, error)
	Delete(ctx context.Context, id int64) (bool, error)
}

Pada kode diatas interface yang nantinya bisa dikomunikasi untuk digunakan pada delivery layer. Dan fungsi-fungsi yang diatas sudah didefinisikan ini akan kita implementasikan satu persatu.

Usecase Fungsi Mengambil Semua Data Article

Pada usecase ini, kita akan coba membuat implementasi dari interface diatas menjadi fungsi implement. Sebelumnya kita perlu buat file pada folder usecase article/article.go dan pertama isi inisialisasi usecase ini dengan kode seperti dibawah ini.

type Usecase struct {
	articleRepository repository.ArticleRepository
}

func New(repo repository.ArticleRepository) *Usecase {
	return &Usecase{articleRepository: repo}
}

Dilanjutkan dengan menambahkan fungsi GetAll() dengan proses didalamnya terdapat akses ke dalam repository yang sudah kita definisikan.

func (u *Usecase) GetAll(ctx context.Context) ([]models.ArticleResponse, error) {
	var response []models.ArticleResponse

	res, err := u.articleRepository.GetAll(ctx)
	if err != nil {
		return response, err
	}

	for _, v := range res {
		response = append(response, v.ToArticleResponse())
	}

	return response, nil
}

Bisa kita lihat, pada usecase ini ada struct baru yang menyimpan data repository layer ke dalam struct usecase layer. Maka ini sangat penting kita bedakan struct-nya agar data yang diambil ke dalam database tidak semuanya kita munculkan dan hanya beberapa field saja yang dimunculkan pada user sesuai dengan kebutuhannya.

Contoh halnya misalkan password, hal ini sangat krusial jika kita langsung mengembalikan ke user maka akan terlihat semua password yang ada setiap user.

Maka, kita perlu buat file article_web.go untuk menampung struct request dan response dari setiap usecase yang kita buat.

type ArticleListResponse struct {
	HeaderResponse
	Data []ArticleResponse
}

type ArticleResponse struct {
	ID       int64
	Title    string
	Content  string
	CreateAt time.Time
	UpdateAt time.Time
}

type HeaderResponse struct {
	Code   int
	Status string
}

Usecase Fungsi Mengambil Data Article ByID

Proses selanjutnya tambahkan fungsi pada usecase seperti ini.

func (u *Usecase) GetByID(ctx context.Context, id int64) (models.ArticleResponse, error) {
	var response models.ArticleResponse

	res, err := u.articleRepository.GetByID(ctx, id)
	if err != nil {
		return response, err
	}

	response = res.ToArticleResponse()
	return response, nil
}

Usecase Fungsi Update Data Article

Seperti dikatakan diatas pernah disinggung, usecase untuk mengupdate data tersebut memiliki logika proses yang terhitung panjang daripada proses logika fungsi lain sehingga bisa kita lihat dibawah ini.

func (u *Usecase) Update(ctx context.Context, request models.ArticleUpdateRequest) (models.ArticleResponse, error) {
	var article = new(models.Article)
	var response models.ArticleResponse

	if request.ID == 0 {
		return response, errors.New("request article_id do not zero or empty")
	}

	// validate data from database was found
	article, err := u.articleRepository.GetByID(ctx, request.ID)
	if err != nil {
		return response, err
	}

	if article.ID == 0 {
		return response, errors.New("data not found")
	}

	// from request to article struct
	article.FromUpdateRequest(request)

	// execute update
	article, err = u.articleRepository.Update(ctx, article)
	if err != nil {
		return response, err
	}

	// append data update to response
	response = article.ToArticleResponse()
	return response, nil
}

Ada beberapa pengecekan kalau kita lihat di proses untuk pengubah data tersebut.

Usecase Fungsi Tambah Data Article

Pada proses usecase untuk tambah data seperti dibawah ini.

func (u *Usecase) Store(ctx context.Context, request models.ArticleCreateRequest) (models.ArticleResponse, error) {
	var article = new(models.Article)
	var response models.ArticleResponse

	// convert request to article struct
	article.FromCreateRequest(request)

	// executed store
	articleID, err := u.articleRepository.Store(ctx, article)
	if err != nil {
		return response, err
	}

	article.ID = articleID
	response = article.ToArticleResponse()
	return response, nil
}

Usecase Fungsi Hapus Data Article

Pada proses usecase hapus data bisa kita lihat ada proses ketika kita melakukan pengecekan terlebih dahulu ke dalam database apakah id tersebut ada atau tidak, jika ada akan dilanjutkan untuk melakukan proses hapus tetapi ketika tidak ditemukan akan muncul error.

func (u *Usecase) Delete(ctx context.Context, id int64) (bool, error) {
	var isSuccss bool

	// validate data from database was found
	article, err := u.articleRepository.GetByID(ctx, id)
	if err != nil {
		return isSuccss, err
	}

	if article == nil {
		return isSuccss, errors.New("article not found")
	}

	isSuccss, err = u.articleRepository.Delete(ctx, id)
	if err != nil {
		return isSuccss, err
	}

	return isSuccss, nil
}
comments powered by Disqus