iT邦幫忙

2024 iThome 鐵人賽

DAY 20
0
Modern Web

Go 快 Go 高效: 從基礎語法到現代Web應用開發系列 第 20

【Day20】RESTful API 設計 II | 寫入方式 (Create、Updata、Delete) 介紹

  • 分享至 

  • xImage
  •  

前言

那我們前一篇教的是查詢的方式,那今天就來介紹如何修改我們資料庫的內容吧!
/images/emoticon/emoticon48.gif


反序列化(Deserialization)

反序列化 是將外部數據格式(如 JSON、XML)轉換回內存中的數據結構。這在處理客戶端發送的請求體時尤為重要,例如從 JSON 請求中提取用戶信息並轉換為 Go 的結構體。


Repository 實現方法

  • Create
func Create(user *models.User) error {
	result := database.DB.Context.Create(user)
	return result.Error
}

使用 GORM 的 Create 方法來將 user 寫入資料庫。Create 方法會自動將資料轉換為 SQL 的 INSERT 語句並執行。

  • Update
func Update(user *models.User) error {
	result := database.DB.Context.Save(user)
	return result.Error
}

使用 GORM 的 Save 方法,這個方法會根據 user 中的主鍵(通常是 ID)來判斷資料是否已存在。如果資料存在,則進行 UPDATE 操作;如果不存在,則進行 INSERT 操作。

  • Delete
func Delete(id uint) error {
	result := database.DB.Context.Delete(&models.User{}, id)
	return result.Error
}

使用 GORM 的 Delete 方法,這個方法會根據傳入的 id 刪除對應的 User 資料。Delete 方法會自動生成一個 DELETE FROM 語句。


Handle 實現方法

  • CreateHandle
func CreateHandle(context *gin.Context) {
	var user models.User

	// 請求 JSON 資料
	if err := context.ShouldBindJSON(&user); err != nil {
		context.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request payload"})
		return
	}

	// 調用 repository 創建用戶
	if err := repositories.Create(&user); err != nil {
		context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
		return
	}

	// 返回創建
	context.JSON(http.StatusCreated, user)
}

context.ShouldBindJSON(&user) 將請求體中的 JSON 數據反序列化到 user 結構體中,並自動執行結構體標籤(models.User)中定義的驗證規則。

  • UpdateHandle
func UpdateHandle(context *gin.Context) {
	var user models.User

	// 從 JSON 請求中獲取資料
	if err := context.ShouldBindJSON(&user); err != nil {
		context.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request payload"})
		return
	}

	// 確認 user.ID 是否存在
	if user.ID == 0 {
		context.JSON(http.StatusBadRequest, gin.H{"error": "User ID is required"})
		return
	}

	// 更新用戶資料
	if err := repositories.Update(&user); err != nil {
		context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user"})
		return
	}

	context.JSON(http.StatusOK, user)
}

當我們使用 ShouldBindJSON 去解析一個 JSON 資料並將它映射到一個結構體(models.User)時,如果 JSON 裡面沒有提供 ID 欄位,這個欄位的值就會是結構體的預設值,即 0

  • DeleteHandle
func DeleteHandle(context *gin.Context) {
	var user models.User

	// 從 JSON 請求中獲取要刪除的用戶 ID
	if err := context.ShouldBindJSON(&user); err != nil {
		context.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request payload"})
		return
	}

	// 確認 user.ID 是否存在
	if user.ID == 0 {
		context.JSON(http.StatusBadRequest, gin.H{"error": "User ID is required"})
		return
	}

	// 刪除用戶資料
	if err := repositories.Delete(user.ID); err != nil {
		context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete user"})
		return
	}

	context.JSON(http.StatusOK, gin.H{"message": "User deleted successfully"})
}

注意事項

特性 BindJSON ShouldBindJSON
錯誤處理 自動返回錯誤回應(400) 開發者需自行處理返回錯誤
靈活性 低,依賴框架的默認錯誤處理 高,允許開發者自定義錯誤處理邏輯
適用場景 簡單的綁定需求,無需自定義錯誤處理 需要自定義錯誤處理或更複雜的綁定邏輯

API測試

Postman

  • CreateHandle
    https://ithelp.ithome.com.tw/upload/images/20240928/20161850gr7fpUkcnv.png

  • UpdateHandle
    https://ithelp.ithome.com.tw/upload/images/20240928/201618503iNiVzQseZ.png

  • DeleteHandle
    https://ithelp.ithome.com.tw/upload/images/20240928/20161850LMNtjXWP7X.png

Apifox

  • CreateHandle
    https://ithelp.ithome.com.tw/upload/images/20240928/20161850dgQrULbtX4.png

  • UpdateHandle
    https://ithelp.ithome.com.tw/upload/images/20240928/20161850pUyCHcO9HL.png

  • DeleteHandle
    https://ithelp.ithome.com.tw/upload/images/20240928/20161850XJf6rV6ma7.png

注意事項

其實我們從 Postman/Apifox 在帶入json內容時,眼睛比較敏銳的可能會發現說,誒我帶的key怎麼大小寫跟我資料庫裡面的名稱設的不一樣,那這是因為我們的models.User在進行 JSON 解析時,會使用大小寫不敏感的配對。如果你想強制規範 JSON 欄位和結構體屬性之間的對應,建議使用標籤 json 來明確定義說限制的輸入格式。


總結

在這篇文章介紹了如何使用 GORM 操作資料庫的增、改、刪功能,並透過 Gin 框架的 ShouldBindJSON 來反序列化 JSON 請求。範例展示了如何創建、更新和刪除使用者資料,並說明了 Gin 框架下不同的錯誤處理方式。


上一篇
【Day19】RESTful API 設計 I | 讀取方式 (Get) 介紹
下一篇
【Day21】Go 中的錯誤處理 | Error Handling 實踐指南
系列文
Go 快 Go 高效: 從基礎語法到現代Web應用開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言