今天來寫上Router層的部分,開始之前,剛剛發現line-bot-sdk-go
更新到了v7版本,那我們也來跟著更新,目前使用到的地方,沒有使用方式要跟著換的,所以我們就趁開發到功能之前先來升級一下~
go get -u github.com/line/line-bot-sdk-go/v7/linebot
// import github.com/line/line-bot-sdk-go/linebot
// 換成下面的
import github.com/line/line-bot-sdk-go/v7/linebot
go mod tidy
一下之後,我們開始來實現Router層
依照習慣先建立v1的資料夾(雖然應該不會有v2 XD),然後新增callback.go和v1.go
callback.go,這邊我們寫上Callback()
,這是給Linebot Webhook調用的function,接受一個Application
物件,並返回一個gin的Handler Function。
// callback.go
package v1
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"github.com/line/line-bot-sdk-go/v7/linebot"
"github.com/onepiece010938/Line2GoogleDriveBot/internal/app"
)
func Callback(app *app.Application) gin.HandlerFunc {
return func(c *gin.Context) {
ctx := c.Request.Context()
events, err := app.LineBotClient.ParseRequest(c.Request)
if err != nil {
if err == linebot.ErrInvalidSignature {
log.Println(err)
c.JSON(http.StatusBadRequest, err)
} else {
log.Println(err)
c.JSON(http.StatusInternalServerError, err)
}
return
}
for _, event := range events {
if event.Type == linebot.EventTypeMessage {
switch message := event.Message.(type) {
case *linebot.TextMessage:
samplePK, err := app.SampleService.Sample(ctx, message.Text)
if err != nil {
log.Println(err)
return
}
if _, err = app.LineBotClient.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(samplePK)).Do(); err != nil {
log.Println(err)
}
}
}
}
}
}
我們可以透過app.LineBotClient
來取得一開始放進來Application
的LineBot Client連線,也可以直接透過app.SampleService.XXX
這樣的方式來調用向app註冊好的Services們,以上面這個例子我們會調用昨天寫好的SampleService.Sample
,將使用者的輸入作為lineID去dynamodb查詢對應的PK值,也就是linebot上輸入 test1234
如果有該筆紀錄會回傳LINE#test1234
。
接著我們到v1.go,寫上RegisterRouter()
,由這裡來註冊v1這個gin Group下的所有路由,並把收到的Application
放進Callback
中。
// v1.go
package v1
import (
"github.com/onepiece010938/Line2GoogleDriveBot/internal/app"
"github.com/gin-gonic/gin"
)
func RegisterRouter(router *gin.RouterGroup, app *app.Application) {
v1 := router.Group("/v1")
{
// 將 /v1/callback 請求路由到 Callback 函數來處理
v1.POST("/callback", Callback(app))
}
}
最後到最外層的router.go,用一個對外的RegisterHandlers
來調用registerAPIHandlers
,並在api group下調用v1的RegisterRouter
來把/v1
註冊進/api
下,如果哪天要更改內部路由的實現方式,這樣的方式就不需要修改外部調用 RegisterHandlers
的部分。
// router.go
package router
import (
"context"
"github.com/onepiece010938/Line2GoogleDriveBot/internal/app"
v1 "github.com/onepiece010938/Line2GoogleDriveBot/internal/router/api/v1"
"github.com/gin-gonic/gin"
)
func RegisterHandlers(router *gin.Engine, app *app.Application) {
registerAPIHandlers(router, app)
}
func registerAPIHandlers(router *gin.Engine, app *app.Application) {
api := router.Group("/api")
{
v1.RegisterRouter(api, app)
}
}
那Router層的部分就先到這,我們明天再把server的部分寫好,就可以整個拉起來跑跑看,那我們明天見~