Pada kali ini, kita akan melanjutkan projek pembuatan RESTFul API menggunakan Golang 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
}