pemrograman

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.

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"
}
comments powered by Disqus