programming

07 Creating a Handler as a Data Delivery Layer

At this stage we will continue the project that we have created by creating a Delivery Layer. This layer as explained earlier is a layer that connects user requests with the logic layer.

In this layer we usually provide some validation for each request sent by the user so that later when sent to the usecase layer the request data is not empty or needs to be validated again.

Alright, let’s go straight to the delivery/http folder and create the article.go file. We created the http folder because the handler we created is a REST API handler which is the http protocol.

Fill the above file with the following.

type Delivery struct {
	articleUsecase usecase.ArticleUsecase
}

func New(articleUsecase usecase.ArticleUsecase) *Delivery {
	return &Delivery{
		articleUsecase: articleUsecase,
	}
}

And we will also create the pkg/util/ folder which will be filled with files that handle the response from the API that we have created into the json data type. Here is the pkg/util/response.go file below.

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)
	}
}

Function Handler to Retrieve All Article Data

In this usecase, we will try to create a function to retrieve all article data with the function name GetAll() as below.

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"
}

Function Handler Retrieving Article ByID Data

The next process adds a function to the handler like this.

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"
}

Kode Sumber 4.3. ## Handler Fungsi Update Data Artikel Seperti yang telah disinggung di atas, handler untuk mengupdate data tersebut akan mengakses usecase fungsi update seperti di bawah ini.

func (d *Pengiriman) 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 di atas.

articleIDString := params.ByName("article_id")

Kemudian 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)

Kode Sumber 4.4. ## Fungsi Handler Tambah Data Artikel Pada proses handler untuk menambah data artikel dapat kita lihat seperti di bawah ini.

func (d *Pengiriman) 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"
}

Kode Sumber 4.7. ## Handler Fungsi Hapus Data Artikel Pada proses usecase hapus data kita membutuhkan parameter dan body request untuk diteruskan ke usecase seperti di bawah ini.

func (d *Pengiriman) Hapus(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 bukan nol"
		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("error tidak diketahui").Error()
		return
	}

	statusCode = http.StatusOK
	response.Code = statusCode
	response.Status = "OK"
}
comments powered by Disqus