06 Membuat Usecase Sebagai Data Logic
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.
1package usecase
2
3import (
4 "context"
5
6 "github.com/santekno/learn-golang-restful/models"
7)
8
9type ArticleUsecase interface {
10 GetAll(ctx context.Context) ([]models.ArticleResponse, error)
11 GetByID(ctx context.Context, id int64) (models.ArticleResponse, error)
12 Update(ctx context.Context, article models.ArticleUpdateRequest) (models.ArticleResponse, error)
13 Store(ctx context.Context, article models.ArticleCreateRequest) (models.ArticleResponse, error)
14 Delete(ctx context.Context, id int64) (bool, error)
15}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.
1type Usecase struct {
2 articleRepository repository.ArticleRepository
3}
4
5func New(repo repository.ArticleRepository) *Usecase {
6 return &Usecase{articleRepository: repo}
7}Dilanjutkan dengan menambahkan fungsi GetAll() dengan proses didalamnya terdapat akses ke dalam repository yang sudah kita definisikan.
1func (u *Usecase) GetAll(ctx context.Context) ([]models.ArticleResponse, error) {
2 var response []models.ArticleResponse
3
4 res, err := u.articleRepository.GetAll(ctx)
5 if err != nil {
6 return response, err
7 }
8
9 for _, v := range res {
10 response = append(response, v.ToArticleResponse())
11 }
12
13 return response, nil
14}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.
1type ArticleListResponse struct {
2 HeaderResponse
3 Data []ArticleResponse
4}
5
6type ArticleResponse struct {
7 ID int64
8 Title string
9 Content string
10 CreateAt time.Time
11 UpdateAt time.Time
12}
13
14type HeaderResponse struct {
15 Code int
16 Status string
17}Usecase Fungsi Mengambil Data Article ByID
Proses selanjutnya tambahkan fungsi pada usecase seperti ini.
1func (u *Usecase) GetByID(ctx context.Context, id int64) (models.ArticleResponse, error) {
2 var response models.ArticleResponse
3
4 res, err := u.articleRepository.GetByID(ctx, id)
5 if err != nil {
6 return response, err
7 }
8
9 response = res.ToArticleResponse()
10 return response, nil
11}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.
1func (u *Usecase) Update(ctx context.Context, request models.ArticleUpdateRequest) (models.ArticleResponse, error) {
2 var article = new(models.Article)
3 var response models.ArticleResponse
4
5 if request.ID == 0 {
6 return response, errors.New("request article_id do not zero or empty")
7 }
8
9 // validate data from database was found
10 article, err := u.articleRepository.GetByID(ctx, request.ID)
11 if err != nil {
12 return response, err
13 }
14
15 if article.ID == 0 {
16 return response, errors.New("data not found")
17 }
18
19 // from request to article struct
20 article.FromUpdateRequest(request)
21
22 // execute update
23 article, err = u.articleRepository.Update(ctx, article)
24 if err != nil {
25 return response, err
26 }
27
28 // append data update to response
29 response = article.ToArticleResponse()
30 return response, nil
31}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.
1func (u *Usecase) Store(ctx context.Context, request models.ArticleCreateRequest) (models.ArticleResponse, error) {
2 var article = new(models.Article)
3 var response models.ArticleResponse
4
5 // convert request to article struct
6 article.FromCreateRequest(request)
7
8 // executed store
9 articleID, err := u.articleRepository.Store(ctx, article)
10 if err != nil {
11 return response, err
12 }
13
14 article.ID = articleID
15 response = article.ToArticleResponse()
16 return response, nil
17}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.
1func (u *Usecase) Delete(ctx context.Context, id int64) (bool, error) {
2 var isSuccss bool
3
4 // validate data from database was found
5 article, err := u.articleRepository.GetByID(ctx, id)
6 if err != nil {
7 return isSuccss, err
8 }
9
10 if article == nil {
11 return isSuccss, errors.New("article not found")
12 }
13
14 isSuccss, err = u.articleRepository.Delete(ctx, id)
15 if err != nil {
16 return isSuccss, err
17 }
18
19 return isSuccss, nil
20}