iT邦幫忙

2025 iThome 鐵人賽

DAY 15
0

我們會分成兩個章節來調整 To-do List 專案架構,主要是將「 有相關聯、會互相影響 」的程式做區分:

第一部分:service、model、middleware、main
第二部分:handler、repository、service

所以,今天會先從第一部分開始介紹!
大家要記得先把 To-do List 專案的檔案建立好!可以對照上一個章節的示意圖,名稱可以自己命名。
完成檔案建置後,就可以移動程式了~


1. model

一開始先來定義 task 資料結構。把會使用到的名稱都先定義好,並且綁定 json tag。

package model

type Task struct {
	ID     int    `json:"id"`
	Item   string `json:"item"`
	Status bool   `json:"status"`
}

type UpdateTask struct {         // PATCH,用指標判斷是否有傳欄位
	Item  *string `json:"item"`
	Status *bool   `json:"status"`
}

2. service

然後建立 Error massage 的錯誤定義,這部分會傳入 middleware 做使用。另外, Error message 要記得使用英文字母小寫唷!除了 Error message 之外,service 檔案裡面還會放 CRUD 的流程,這部分明天再一起介紹。

package taskService

import (
	"errors"
)

// Error messages
var (
	ErrNotFound      = errors.New("task not found")
	ErrInvalidInput	 = errors.New("input could not be null")
	ErrInvalidID     = errors.New("invalid id")
)

3. middleware

建立回傳的 Error massage。這邊的 Error message 會呼叫剛剛在 service 檔案裡面定義的錯誤(taskService.~)。然後當我們呼叫時這個函式時,就會自動找出要回應的對應錯誤內容。

package middleware

import (
	"errors"
	"net/http"
	"app/service"
	"github.com/gin-gonic/gin"
)

func ErrorHandler() gin.HandlerFunc { 
	return func(c *gin.Context) {
		c.Next() 	

		if len(c.Errors) == 0 {
			return
		}

		err := c.Errors.Last().Err

		var status int
		var msg string

		switch {
            // 帶入剛剛在 service 定義的錯誤訊息
			case errors.Is(err, taskService.ErrNotFound): 
				status = http.StatusNotFound
				msg = err.Error()

			case errors.Is(err, taskService.ErrInvalidID):
				status = http.StatusBadRequest
				msg = err.Error()

			case errors.Is(err, taskService.ErrInvalidInput):
				status = http.StatusBadRequest
				msg = err.Error()

			default:
				status = http.StatusInternalServerError
				msg = "internal server error"
		}
		c.AbortWithStatusJSON(status, gin.H{"error": msg})
	}
}


4. main

最後,main.go 主要就是放 啟動 server 和一些路由的設置。這部分需要留意的地方是建立路由 r.GET("/tasks", apiHandler.GetTasks) 的部分,這一個 apiHandler.GetTasks 是對應到 apiHandler 裡面的 function,所以函式名稱記得要大寫。

package main

import (
	"app/apiHandler"
	"app/middleware"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.Use(middleware.ErrorHandler())

	r.GET("/tasks", apiHandler.GetTasks)
	r.POST("/tasks", apiHandler.AddTask)
	r.PATCH("/tasks/:id", apiHandler.UpdateTask)
	r.DELETE("/tasks/:id", apiHandler.DeleteTask)

	r.Run(":8080")
}

明天會再繼續把剩下的部分完善!


上一篇
Day14 - 實務開發中的 GO 專案架構
系列文
Go,一起成為全端吧!—— 給前端工程師的 Golang 後端學習筆記15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言