Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/880831ian/go-restful-api-repository-messageboard
使用 Go 來寫一個 Repository Restful API 的留言板,並且會使用 gin 以及 gorm (使用 Mysql)套件。
https://github.com/880831ian/go-restful-api-repository-messageboard
gin go golang gorm messageboard repository restful restful-api
Last synced: 3 days ago
JSON representation
使用 Go 來寫一個 Repository Restful API 的留言板,並且會使用 gin 以及 gorm (使用 Mysql)套件。
- Host: GitHub
- URL: https://github.com/880831ian/go-restful-api-repository-messageboard
- Owner: 880831ian
- Created: 2022-03-29T09:16:06.000Z (almost 3 years ago)
- Default Branch: master
- Last Pushed: 2022-04-04T02:54:49.000Z (almost 3 years ago)
- Last Synced: 2024-12-23T13:07:38.621Z (11 days ago)
- Topics: gin, go, golang, gorm, messageboard, repository, restful, restful-api
- Language: Go
- Homepage:
- Size: 617 KB
- Stars: 5
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
本文章是使用 Go 來寫一個 Repository Restful API 的留言板,並且會使用 gin 以及 gorm (使用 Mysql)套件。
建議可以先觀看 [Go 介紹](https://pin-yi.me/go/) 文章來簡單學習 Go 語言。
版本資訊
* macOS:11.6
* Go:go version go1.18 darwin/amd64
* Mysql:mysql Ver 8.0.28 for macos11.6 on x86_64 (Homebrew)## 實作
### 檔案結構
```
.
├── controller
│ └── controller.go
├── go.mod
├── go.sum
├── main.go
├── model
│ └── model.go
├── repository
│ └── repository.go
├── router
│ └── router.go
└── sql
├── connect.yaml
└── sql.go
```
我們來說明一下上面的資料夾個別功能與作用
* sql:放置連線資料庫檔案。
* controller:商用邏輯控制。
* model:定義資料表資料型態。
* repository:處理與資料庫進行交握。
* router:設定網站網址路由。### go.mod
一開始我們創好資料夾後,要先來設定 go.mod 的 module
```sh
$ go mod init message
```* go.mod 檔案
```sh
module messagego 1.18
```
接著使用 `go get` 來引入 `gin`、`gorm`、`mysql`、`yaml` 套件
```sh
$ go get -u github.com/gin-gonic/gin
$ go get -u gorm.io/gorm
$ go get -u gorm.io/driver/mysql
$ go get -u gopkg.in/yaml.v2
```
可以在查看一下 go.mod 檔案是否多了很多 indirect
### main.go
```go
package mainimport (
"fmt"
"message/model"
"message/router"
"message/sql"
)func main() {
//連線資料庫
if err := sql.InitMySql(); err != nil {
panic(err)
}
//連結模型
sql.Connect.AutoMigrate(&model.Message{})
//sql.Connect.Table("message") //也可以使用連線已有資料表方式
//註冊路由
r := router.SetRouter()
//啟動埠為8081的專案
fmt.Println("開啟127.0.0.0.1:8081...")
r.Run("127.0.0.1:8081")
}
```
引入我們 Repository 架構,將 config、model、router 導入,先測試是否可以連線資料庫,使用 `AutoMigrate` 來新增資料表(如果沒有才新增),或是使用 Table 來連線已有資料表,註冊網址路由,最後啟動專案,我們將 Port 設定成 8081。
### sql
我們剛剛有引入 `yaml` 套件,因為我們設定檔案會使用 yaml 來編輯
* connect.yaml
```yaml
host: 127.0.0.1
username: root
password: "密碼"
dbname: "資料庫名稱"
port: 3306
```
我們把 mysql 連線的資訊寫在此處。
* sql.go (下面為一個檔案,但長度有點長,分開說明)
```go
package sqlimport (
"io/ioutil"
"fmt"
"gopkg.in/yaml.v2"
"gorm.io/gorm"
"gorm.io/driver/mysql"
)
```
import 會使用到的套件。
```go
var Connect *gorm.DBtype conf struct {
Host string `yaml:"host"`
UserName string `yaml:"username"`
Password string `yaml:"password"`
DbName string `yaml:"dbname"`
Port string `yaml:"port"`
}func (c *conf) getConf() *conf {
//讀取config/connect.yaml檔案
yamlFile, err := ioutil.ReadFile("sql/connect.yaml")
//若出現錯誤,列印錯誤訊息
if err != nil {
fmt.Println(err.Error())
}
//將讀取的字串轉換成結構體conf
err = yaml.Unmarshal(yamlFile, c)
if err != nil {
fmt.Println(err.Error())
}
return c
}
```
設定資料庫連線的 conf 來讀取 yaml 檔案。
```go
//初始化連線資料庫
func InitMySql() (err error) {
var c conf
//獲取yaml配置引數
conf := c.getConf()
//將yaml配置引數拼接成連線資料庫的url
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
conf.UserName,
conf.Password,
conf.Host,
conf.Port,
conf.DbName,
)
//連線資料庫
Connect, err = gorm.Open(mysql.New(mysql.Config{DSN: dsn}), &gorm.Config{})
return
}
```
初始化資料庫,會把剛剛讀取 yaml 的 conf 串接成可以連接資料庫的 url ,最後連線資料庫。
### router.go
```go
package routerimport (
"message/controller"
"github.com/gin-gonic/gin"
)func SetRouter() *gin.Engine {
//顯示 debug 模式
gin.SetMode(gin.ReleaseMode)
r := gin.Default()v1 := r.Group("api/v1")
{
//新增留言
v1.POST("/message", controller.Create)
//查詢全部留言
v1.GET("/message", controller.GetAll)
//查詢 {id} 留言
v1.GET("/message/:id", controller.Get)
//修改 {id} 留言
v1.PATCH("/message/:id", controller.Update)
//刪除 {id} 留言
v1.DELETE("/message/:id", controller.Delete)
}
return r
}
```
設定路由,版本 v1 網址是 `api/v1` ,分別是新增留言、查詢全部留言、查詢 {id} 留言、修改 {id} 留言、刪除 {id} 留言,連接到不同的 `controller` function 。
### model.go
```go
package modelimport "gorm.io/gorm"
func (Message) TableName() string {
return "message"
}type Message struct {
Id int `gorm:"primary_key,type:INT;not null;AUTO_INCREMENT"`
User_Id int `json:"User_Id" binding:"required"`
Content string `json:"Content" binding:"required"`
Version int `gorm:"default:0"`
// 包含 CreatedAt 和 UpdatedAt 和 DeletedAt 欄位
gorm.Model
}
```
設定資料表的結構,使用 gorm.Model 預設裡面會包含 CreatedAt 和 UpdatedAt 和 DeletedAt 欄位。
### controller.go
**(下面為一個檔案,但長度有點長,分開說明)**
```go
package controllerimport (
"message/model"
"message/repository"
"net/http"
"unicode/utf8""github.com/gin-gonic/gin"
)
```
import 會使用到的套件。
**查詢留言功能**
```go
func GetAll(c *gin.Context) {
message, err := repository.GetAllMessage()if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": message})
}func Get(c *gin.Context) {
var message model.Messageif err := repository.GetMessage(&message, c.Param("id")); err != nil {
c.JSON(http.StatusNotFound, gin.H{"message": "找不到留言"})
return
}
c.JSON(http.StatusOK, gin.H{"message": message})
}
```
`GetAll()` 會使用到 `repository.GetAllMessage()` 查詢並回傳顯示查詢的資料。`c.Param("id")` 是網址讀入後的 id,網址是`http://127.0.0.1:8081/api/v1/message/{id}` ,將輸入的 id 透過 `repository.GetMessage()` 查詢並回傳顯示查詢的資料。
**新增留言功能**
```go
func Create(c *gin.Context) {
var message model.Messageif c.PostForm("Content") == "" || utf8.RuneCountInString(c.PostForm("Content")) >= 20 {
c.JSON(http.StatusBadRequest, gin.H{"message": "沒有輸入內容或長度超過20個字元"})
return
}c.Bind(&message)
repository.CreateMessage(&message)
c.JSON(http.StatusCreated, gin.H{"message": message})
}
```使用 Gin 框架中的 `Bind 函數`,可以將 url 的查詢參數 query parameter,http 的 Header、body 中提交的數據給取出,透過 `repository.CreateMessage()` 將要新增的資料帶入,如果失敗就顯示 `http.StatusBadRequest`,如果成功就顯示 `http.StatusCreated` 以及新增的資料。
**修改留言功能**
```go
func Update(c *gin.Context) {
var message model.Messageif c.PostForm("Content") == "" || utf8.RuneCountInString(c.PostForm("Content")) >= 20 {
c.JSON(http.StatusBadRequest, gin.H{"message": "沒有輸入內容或長度超過20個字元"})
return
}if err := repository.UpdateMessage(&message, c.PostForm("Content"), c.Param("id")); err != nil {
c.JSON(http.StatusNotFound, gin.H{"message": "找不到留言"})
return
}
c.JSON(http.StatusOK, gin.H{"message": message})
}
```先使用 `repository.GetMessage()` 以及 `c.Param("id")` 來查詢此 id 是否存在,再帶入要修改的 `Content` ,透過 `repository.UpdateMessage()` 將資料修改,,如果失敗就顯示 `http.StatusNotFound` 以及找不到留言,如果成功就顯示 `http.StatusOK` 以及修改的資料。
**刪除留言功能**
```go
func Delete(c *gin.Context) {
var message model.Messageif err := repository.DeleteMessage(&message, c.Param("id")); err != nil {
c.JSON(http.StatusNotFound, gin.H{"message": "找不到留言"})
return
}
c.JSON(http.StatusNoContent, gin.H{"message": "刪除留言成功"})
}
```透過 `repository.DeleteMessage()` 將資料刪除,如果失敗就顯示 `http.StatusNotFound ` 以及找不到留言,如果成功就顯示 `http.StatusNoContent`。
### repository.go
**(下面為一個檔案,但長度有點長,分開說明)**
所有的邏輯判斷都要在 controller 處理,所以 repository.go 就單純對資料庫就 CRUD:
```go
package repositoryimport (
"message/model"
"message/sql"
)
```
import 會使用到的套件。
**查詢留言資料讀取**
```go
//查詢全部留言
func GetAllMessage() (message []*model.Message, err error) {
err = sql.Connect.Find(&message).Error
return
}//查詢 {id} 留言
func GetMessage(message *model.Message, id string) (err error) {
err = sql.Connect.Where("id=?", id).First(&message).Error
return
}
```
**新增留言資料讀取**
```go
//新增留言
func CreateMessage(message *model.Message) (err error) {
err = sql.Connect.Create(&message).Error
return
}
```
**修改留言資料讀取**
```go
//更新 {id} 留言
func UpdateMessage(message *model.Message, content, id string) (err error) {
err = sql.Connect.Where("id=?", id).First(&message).Update("content", content).Error
return
}
```
**刪除留言資料讀取**
```go
//刪除 {id} 留言
func DeleteMessage(message *model.Message, id string) (err error) {
err = sql.Connect.Where("id=?", id).First(&message).Delete(&message).Error
return
}
```
## Postman 測試
### 查詢全部留言 - 成功(無資料)
![圖片](https://raw.githubusercontent.com/880831ian/go-restful-api-repository-messageboard/master/images/get-success-1.png)
### 查詢全部留言 - 成功(有資料)
![圖片](https://raw.githubusercontent.com/880831ian/go-restful-api-repository-messageboard/master/images/get-success-2.png)
### 查詢{id}留言 - 成功
![圖片](https://raw.githubusercontent.com/880831ian/go-restful-api-repository-messageboard/master/images/get-id-succes.png)
### 查詢{id}留言 - 失敗
![圖片](https://raw.githubusercontent.com/880831ian/go-restful-api-repository-messageboard/master/images/get-error.png)
### 新增留言 - 成功
![圖片](https://raw.githubusercontent.com/880831ian/go-restful-api-repository-messageboard/master/images/create.png)
### 修改{id}留言 - 成功
![圖片](https://raw.githubusercontent.com/880831ian/go-restful-api-repository-messageboard/master/images/patch-success.png)
### 修改{id}留言 - 失敗
![圖片](https://raw.githubusercontent.com/880831ian/go-restful-api-repository-messageboard/master/images/patch-error.png)
### 刪除{id}留言 - 成功
![圖片](https://raw.githubusercontent.com/880831ian/go-restful-api-repository-messageboard/master/images/delete.png)
### 執行結果
![圖片](https://raw.githubusercontent.com/880831ian/go-restful-api-repository-messageboard/master/images/gin-cli.png)
## 參考資料
[基於Gin+Gorm框架搭建MVC模式的Go語言後端系統](https://iter01.com/609571.html)