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.
type Delivery struct {
articleUsecase usecase.ArticleUsecase
}
func New(articleUsecase usecase.ArticleUsecase) *Delivery {
return &Delivery{
articleUsecase: articleUsecase,
}
}
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.
package util
import (
"encoding/json"
"net/http"
)
func Response(w http.ResponseWriter, response interface{}, statusCode int) {
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(statusCode)
encoder := json.NewEncoder(w)
err := encoder.Encode(response)
if err != nil {
panic(err)
}
}
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.
func (d *Delivery) GetAll(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
var response models.ArticleListResponse
var statusCode int = http.StatusBadRequest
defer func() {
util.Response(w, response, statusCode)
}()
res, err := d.articleUsecase.GetAll(r.Context())
if err != nil {
statusCode = http.StatusInternalServerError
response.Code = statusCode
response.Status = err.Error()
return
}
statusCode = http.StatusOK
response.Data = append(response.Data, res...)
response.Code = statusCode
response.Status = "OK"
}
Handler Fungsi Mengambil Data Article ByID
Proses selanjutnya tambahkan fungsi pada handler seperti ini.
func (d *Delivery) GetByID(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
var response models.ArticleListResponse
var statusCode int
defer func() {
util.Response(w, response, statusCode)
}()
articleIDString := params.ByName("article_id")
articleID, err := strconv.ParseInt(articleIDString, 0, 64)
if err != nil {
statusCode = http.StatusBadRequest
response.Code = statusCode
response.Status = err.Error()
return
}
res, err := d.articleUsecase.GetByID(r.Context(), articleID)
if err != nil {
statusCode = http.StatusInternalServerError
response.Code = statusCode
response.Status = err.Error()
return
}
if res.ID == 0 {
statusCode = http.StatusNotFound
response.Code = statusCode
response.Status = "data not found"
return
}
statusCode = http.StatusOK
response.Data = append(response.Data, res)
response.Code = statusCode
response.Status = "OK"
}
Handler Fungsi Update Data Article
Seperti dikatakan diatas pernah disinggung, handler untuk mengupdate data tersebut akan mengakses usecase fungsi update seperti dibawah ini.
func (d *Delivery) Update(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
var response models.ArticleListResponse
var request models.ArticleUpdateRequest
var statusCode = http.StatusBadRequest
defer func() {
util.Response(w, response, statusCode)
}()
articleIDString := params.ByName("article_id")
articleID, err := strconv.ParseInt(articleIDString, 0, 64)
if err != nil {
statusCode = http.StatusBadRequest
response.Code = statusCode
response.Status = err.Error()
return
}
decoder := json.NewDecoder(r.Body)
err = decoder.Decode(&request)
if err != nil {
statusCode = http.StatusBadRequest
response.Code = statusCode
response.Status = err.Error()
return
}
request.ID = articleID
err = d.validate.Struct(request)
if err != nil {
statusCode = http.StatusBadRequest
response.Code = statusCode
response.Status = err.Error()
return
}
res, err := d.articleUsecase.Update(r.Context(), request)
if err != nil {
statusCode = http.StatusInternalServerError
response.Code = statusCode
response.Status = err.Error()
return
}
statusCode = http.StatusOK
response.Data = append(response.Data, res)
response.Code = statusCode
response.Status = "OK"
}
Pada saat update ini kita memerlukan article_id
maka perlu ambil data tersebut dari parameter dengan mengambil id tersebut seperti diatas.
articleIDString := 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.
decoder := json.NewDecoder(r.Body)
err = decoder.Decode(&request)
Handler Fungsi Tambah Data Article
Pada proses handler untuk tambah data artikel bisa kita lihat seperti dibawah ini.
func (d *Delivery) Store(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
var response models.ArticleListResponse
var request models.ArticleCreateRequest
var statusCode int = http.StatusBadRequest
defer func() {
util.Response(w, response, statusCode)
}()
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&request)
if err != nil {
statusCode = http.StatusBadRequest
response.Code = statusCode
response.Status = err.Error()
return
}
err = d.validate.Struct(request)
if err != nil {
statusCode = http.StatusBadRequest
response.Code = statusCode
response.Status = err.Error()
return
}
res, err := d.articleUsecase.Store(r.Context(), request)
if err != nil {
statusCode = http.StatusInternalServerError
response.Code = statusCode
response.Status = err.Error()
return
}
response.Data = append(response.Data, res)
statusCode = http.StatusOK
response.Code = statusCode
response.Status = "OK"
}
Handler Fungsi Hapus Data Article
Pada proses usecase hapus data kita membutuhkan parameter dan body request untuk diteruskan ke usecase seperti dibawah ini.
func (d *Delivery) Delete(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
var response models.ArticleListResponse
var statusCode int = http.StatusBadRequest
defer func() {
util.Response(w, response, statusCode)
}()
articleIDString := params.ByName("article_id")
articleID, err := strconv.ParseInt(articleIDString, 0, 64)
if err != nil {
statusCode = http.StatusBadRequest
response.Code = statusCode
response.Status = err.Error()
return
}
if articleID == 0 {
statusCode = http.StatusBadRequest
response.Code = statusCode
response.Status = "article_id was not zero"
return
}
res, err := d.articleUsecase.Delete(r.Context(), articleID)
if err != nil {
statusCode = http.StatusInternalServerError
response.Code = statusCode
response.Status = err.Error()
return
}
if !res {
statusCode = http.StatusInternalServerError
response.Code = statusCode
response.Status = errors.New("unknown error").Error()
return
}
statusCode = http.StatusOK
response.Code = statusCode
response.Status = "OK"
}