07 Membuat Handler Sebagai Data Delivery Layer
Pada tahapan ini kita akan melanjutkan projek yang sudah kita buat dengan membuat Delivery Layer. Layer ini seperti yang dijelaskan sebelumnya yaitu layer yang menghubungkan request user dengan logic layer.
Pada layer ini kita biasanya memberikan beberapa validasi untuk setiap request yang dikirim oleh user sehingga nanti pada saat dikirim ke usecase layer data request itu tidak ada yang kosong atau perlu di validasi kembali.
Baiklah, kita langsung saja ke folder delivery/http dan buat file article.go. Kita buat folder http karena handler yang kita buat itu merupakan handler REST API yang mana itu adalah protokol http.
Isi file diatas itu dengan seperti dibawah ini.
1type Delivery struct {
2 articleUsecase usecase.ArticleUsecase
3}
4
5func New(articleUsecase usecase.ArticleUsecase) *Delivery {
6 return &Delivery{
7 articleUsecase: articleUsecase,
8 }
9}Dan kita juga akan membuat folder pkg/util/ yang mana akan diisi oleh file yang menghandle response dari API yang sudah kita buat menjadi tipe data json. Berikut file pkg/util/response.go dibawah ini.
1package util
2
3import (
4 "encoding/json"
5 "net/http"
6)
7
8func Response(w http.ResponseWriter, response interface{}, statusCode int) {
9 w.Header().Add("Content-Type", "application/json")
10 w.WriteHeader(statusCode)
11 encoder := json.NewEncoder(w)
12 err := encoder.Encode(response)
13 if err != nil {
14 panic(err)
15 }
16}Handler Fungsi Mengambil Semua Data Article
Pada usecase ini, kita akan coba membuat fungsi untuk mengambil semua data artikel dengan nama fungsi GetAll() seperti dibawah ini.
1func (d *Delivery) GetAll(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
2 var response models.ArticleListResponse
3 var statusCode int = http.StatusBadRequest
4
5 defer func() {
6 util.Response(w, response, statusCode)
7 }()
8
9 res, err := d.articleUsecase.GetAll(r.Context())
10 if err != nil {
11 statusCode = http.StatusInternalServerError
12 response.Code = statusCode
13 response.Status = err.Error()
14 return
15 }
16
17 statusCode = http.StatusOK
18 response.Data = append(response.Data, res...)
19 response.Code = statusCode
20 response.Status = "OK"
21}Handler Fungsi Mengambil Data Article ByID
Proses selanjutnya tambahkan fungsi pada handler seperti ini.
1func (d *Delivery) GetByID(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
2 var response models.ArticleListResponse
3 var statusCode int
4
5 defer func() {
6 util.Response(w, response, statusCode)
7 }()
8
9 articleIDString := params.ByName("article_id")
10 articleID, err := strconv.ParseInt(articleIDString, 0, 64)
11 if err != nil {
12 statusCode = http.StatusBadRequest
13 response.Code = statusCode
14 response.Status = err.Error()
15 return
16 }
17
18 res, err := d.articleUsecase.GetByID(r.Context(), articleID)
19 if err != nil {
20 statusCode = http.StatusInternalServerError
21 response.Code = statusCode
22 response.Status = err.Error()
23 return
24 }
25
26 if res.ID == 0 {
27 statusCode = http.StatusNotFound
28 response.Code = statusCode
29 response.Status = "data not found"
30 return
31 }
32
33 statusCode = http.StatusOK
34 response.Data = append(response.Data, res)
35 response.Code = statusCode
36 response.Status = "OK"
37}Handler Fungsi Update Data Article
Seperti dikatakan diatas pernah disinggung, handler untuk mengupdate data tersebut akan mengakses usecase fungsi update seperti dibawah ini.
1func (d *Delivery) Update(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
2 var response models.ArticleListResponse
3 var request models.ArticleUpdateRequest
4 var statusCode = http.StatusBadRequest
5
6 defer func() {
7 util.Response(w, response, statusCode)
8 }()
9
10 articleIDString := params.ByName("article_id")
11 articleID, err := strconv.ParseInt(articleIDString, 0, 64)
12 if err != nil {
13 statusCode = http.StatusBadRequest
14 response.Code = statusCode
15 response.Status = err.Error()
16 return
17 }
18
19 decoder := json.NewDecoder(r.Body)
20 err = decoder.Decode(&request)
21 if err != nil {
22 statusCode = http.StatusBadRequest
23 response.Code = statusCode
24 response.Status = err.Error()
25 return
26 }
27
28 request.ID = articleID
29
30 err = d.validate.Struct(request)
31 if err != nil {
32 statusCode = http.StatusBadRequest
33 response.Code = statusCode
34 response.Status = err.Error()
35 return
36 }
37
38 res, err := d.articleUsecase.Update(r.Context(), request)
39 if err != nil {
40 statusCode = http.StatusInternalServerError
41 response.Code = statusCode
42 response.Status = err.Error()
43 return
44 }
45
46 statusCode = http.StatusOK
47 response.Data = append(response.Data, res)
48 response.Code = statusCode
49 response.Status = "OK"
50}Pada saat update ini kita memerlukan article_id maka perlu ambil data tersebut dari parameter dengan mengambil id tersebut seperti diatas.
1articleIDString := params.ByName("article_id")Lalu ketika kita ingin mengambil body dari suatu request protokol http kita bisa menggunakan decode juga untuk dikonversikan ke dalam struct yang sudah kita buat.
1 decoder := json.NewDecoder(r.Body)
2 err = decoder.Decode(&request)Handler Fungsi Tambah Data Article
Pada proses handler untuk tambah data artikel bisa kita lihat seperti dibawah ini.
1func (d *Delivery) Store(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
2 var response models.ArticleListResponse
3 var request models.ArticleCreateRequest
4 var statusCode int = http.StatusBadRequest
5
6 defer func() {
7 util.Response(w, response, statusCode)
8 }()
9
10 decoder := json.NewDecoder(r.Body)
11 err := decoder.Decode(&request)
12 if err != nil {
13 statusCode = http.StatusBadRequest
14 response.Code = statusCode
15 response.Status = err.Error()
16 return
17 }
18
19 err = d.validate.Struct(request)
20 if err != nil {
21 statusCode = http.StatusBadRequest
22 response.Code = statusCode
23 response.Status = err.Error()
24 return
25 }
26
27 res, err := d.articleUsecase.Store(r.Context(), request)
28 if err != nil {
29 statusCode = http.StatusInternalServerError
30 response.Code = statusCode
31 response.Status = err.Error()
32 return
33 }
34
35 response.Data = append(response.Data, res)
36 statusCode = http.StatusOK
37 response.Code = statusCode
38 response.Status = "OK"
39}Handler Fungsi Hapus Data Article
Pada proses usecase hapus data kita membutuhkan parameter dan body request untuk diteruskan ke usecase seperti dibawah ini.
1func (d *Delivery) Delete(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
2 var response models.ArticleListResponse
3 var statusCode int = http.StatusBadRequest
4
5 defer func() {
6 util.Response(w, response, statusCode)
7 }()
8
9 articleIDString := params.ByName("article_id")
10 articleID, err := strconv.ParseInt(articleIDString, 0, 64)
11 if err != nil {
12 statusCode = http.StatusBadRequest
13 response.Code = statusCode
14 response.Status = err.Error()
15 return
16 }
17
18 if articleID == 0 {
19 statusCode = http.StatusBadRequest
20 response.Code = statusCode
21 response.Status = "article_id was not zero"
22 return
23 }
24
25 res, err := d.articleUsecase.Delete(r.Context(), articleID)
26 if err != nil {
27 statusCode = http.StatusInternalServerError
28 response.Code = statusCode
29 response.Status = err.Error()
30 return
31 }
32
33 if !res {
34 statusCode = http.StatusInternalServerError
35 response.Code = statusCode
36 response.Status = errors.New("unknown error").Error()
37 return
38 }
39
40 statusCode = http.StatusOK
41 response.Code = statusCode
42 response.Status = "OK"
43}