??這是系列文章的第二篇乒省。下面是另外兩篇的鏈接:
??如何使用 Gin 和 Gorm 搭建一個簡單的 API 服務(wù)(一)
??如何使用 Gin 和 Gorm 搭建一個簡單的 API 服務(wù)(三)
創(chuàng)建 API
??我們之前已經(jīng)跑過 Gin 框架的代碼资盅,現(xiàn)在是時候加些功能進(jìn)去了古程。
讀取全部信息
??我們先從"增刪改查"中的"查"入手礁鲁,查詢我們之前添加的信息待侵。我接下來要刪除幾行代碼陌选,并把 Gin 的框架代碼加回來替蔬。
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
var db *gorm.DB
var err error
type Person struct {
ID uint `json:"id”`
FirstName string `json:"firstname”`
LastName string `json:"lastname”`
}
func main() {
// NOTE: See we’re using = to assign the global var
// instead of := which would assign it only in this function
db, err = gorm.Open("sqlite3", "./gorm.db")
if err != nil {
fmt.Println(err)
}
defer db.Close()
db.AutoMigrate(&Person{})
r := gin.Default()
r.GET("g/", GetProjects)
r.Run("g:8080")
}
func GetProjects(c *gin.Context) {
var people []Person
if err := db.Find(&people).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, people)
}
}
??那么運(yùn)行程序厨幻,并在瀏覽器中訪問 http://localhost:8080相嵌,你應(yīng)該看到:
[{“id”: 1,”firstname”: “John”,”lastname”: “Doe”}]
??喔,幾行代碼我們就可以拿到 API 服務(wù)器的響應(yīng)了况脆,而且大部分代碼都是用來錯誤處理的饭宾。
讀取特定信息
??好,為了把 API 接口寫的更符合 REST 規(guī)范格了,我們加入查詢特定信息的借口
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
var db *gorm.DB
var err error
type Person struct {
ID uint `json:"id”`
FirstName string `json:"firstname”`
LastName string `json:"lastname”`
}
func main() {
// NOTE: See we’re using = to assign the global var
// instead of := which would assign it only in this function
db, err = gorm.Open("sqlite3", "./gorm.db")
if err != nil {
fmt.Println(err)
}
defer db.Close()
db.AutoMigrate(&Person{})
r := gin.Default()
r.GET("g/", GetProjects)
r.GET("/people/:id", GetPerson)
r.Run("g:8080")
}
func GetProjects(c *gin.Context) {
var people []Person
if err := db.Find(&people).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, people)
}
}
func GetPerson(c *gin.Context) {
id := c.Params.ByName("id")
var person Person
if err := db.Where("id = ?", id).First(&person).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, person)
}
}
??現(xiàn)在運(yùn)行程序看铆,但請注意,如果要訪問全部信息盛末,你需要訪問的地址變成了 http://localhost:8080/people/ 弹惦,如果 在 URL 的末尾加入了 ID否淤,你就會得到特定的信息 http://localhost:8080/people/1
{"id": 1, "firstname": "John", "lastname": "Doe"}
添加信息
??只有一條記錄是看不大出來查詢?nèi)啃畔⒑筒樵儐螚l信息的區(qū)別的,所以咱們來把添加信息的功能加上吧棠隐。
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
var db *gorm.DB
var err error
type Person struct {
ID uint `json:"id”`
FirstName string `json:"firstname”`
LastName string `json:"lastname”`
}
func main() {
// NOTE: See we’re using = to assign the global var
// instead of := which would assign it only in this function
db, err = gorm.Open("sqlite3", "./gorm.db")
if err != nil {
fmt.Println(err)
}
defer db.Close()
db.AutoMigrate(&Person{})
r := gin.Default()
r.GET("g/", GetProjects)
r.GET("/people/:id", GetPerson)
r.POST("/people", CreatePerson)
r.Run("g:8080")
}
func GetProjects(c *gin.Context) {
var people []Person
if err := db.Find(&people).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, people)
}
}
func GetPerson(c *gin.Context) {
id := c.Params.ByName("id")
var person Person
if err := db.Where("id = ?", id).First(&person).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, person)
}
}
func CreatePerson(c *gin.Context) {
var person Person
c.BindJSON(&person)
db.Create(&person)
c.JSON(200, person)
}
??接下來讓我們從終端運(yùn)行 curl 命令測試一下新加的功能是不是可用石抡,當(dāng)然還是先要把程序運(yùn)行起來。
??在終端運(yùn)行:
$ curl -i -X POST http://localhost:8080/people -d '{ "FirstName": "Elvis", "LastName": "Presley"}'
??應(yīng)該會看到成功的響應(yīng)消息:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Sat, 03 Dec 2016 00:14:06 GMT
Content-Length: 50
{"id":2,"firstname":"Elvis","lastname":"Presley"}
??現(xiàn)在我們訪問一下查詢?nèi)啃畔⒌慕涌冢?a href="http://localhost:8080/people/" target="_blank" rel="nofollow">http://localhost:8080/people/
[{"id": 1,"firstname": "John","lastname": "Doe"},{"id": 2,"firstname": "Elvis","lastname": "Presley"}]
??太棒啦助泽,代碼沒問題啰扛。這回我們只發(fā)送 Person 結(jié)構(gòu)體的部分信息,看看程序會如何處理嗡贺。
$ curl -i -X POST http://localhost:8080/people -d '{ "FirstName": "Madison"}'
??刷新一下瀏覽器侠讯,發(fā)現(xiàn)只添加了我們發(fā)送的信息。
[{"id": 1,"firstname": "John","lastname": "Doe"},{"id": 2,"firstname": "Elvis","lastname": "Presley"},{"id": 3,"firstname": "Madison","lastname": ""}]
??這就是 Gin 如何工作的了暑刃,留意一下 c.BindJSON(&person)
這行厢漩,它會自動匹配請求消息中的數(shù)據(jù)信息。
??雖然請求消息里可能缺某些信息岩臣,就比如剛才那個例子溜嗜,而且大小寫不匹配也沒有關(guān)系,Gin 的容錯性非常高架谎。非常簡單炸宵!
更新信息
??我們不能把 Madison 這條記錄沒有姓氏啊,是時候加入更新功能了谷扣。
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
var db *gorm.DB
var err error
type Person struct {
ID uint `json:"id"`
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
}
func main() {
// NOTE: See we're using = to assign the global var
// instead of := which would assign it only in this function
db, err = gorm.Open("sqlite3", "./gorm.db")
if err != nil {
fmt.Println(err)
}
defer db.Close()
db.AutoMigrate(&Person{})
r := gin.Default()
r.GET("g/", GetProjects)
r.GET("/people/:id", GetPerson)
r.POST("/people", CreatePerson)
r.PUT("/people/:id", UpdatePerson)
r.Run("g:8080")
}
func GetProjects(c *gin.Context) {
var people []Person
if err := db.Find(&people).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, people)
}
}
func GetPerson(c *gin.Context) {
id := c.Params.ByName("id")
var person Person
if err := db.Where("id = ?", id).First(&person).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, person)
}
}
func CreatePerson(c *gin.Context) {
var person Person
c.BindJSON(&person)
db.Create(&person)
c.JSON(200, person)
}
func UpdatePerson(c *gin.Context) {
var person Person
id := c.Params.ByName("id")
if err := db.Where("id = ?", id).First(&person).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
}
c.BindJSON(&person)
db.Save(&person)
c.JSON(200, person)
}
??這次我們用類似的 curl 命令 進(jìn)行測試土全,但不同的是用 PUT 方法,而且是用在特定的信息上会涎。
$ curl -i -X PUT http://localhost:8080/people/3 -d '{ "FirstName": "Madison", "LastName":"Sawyer" }'
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Sat, 03 Dec 2016 00:25:35 GMT
Content-Length: 51
{"id":3,"firstname":"Madison","lastname":"Sawyer"}
??當(dāng)然更新瀏覽器后裹匙,我們就可以看見 "sawyer" 添加到了 "LastName" 一欄里。
[{"id": 1,"firstname": "John","lastname": "Doe"},{"id": 2,"firstname": "Elvis","lastname": "Presley"},{"id": 3,"firstname": "Madison","lastname": "Sawyer"}]
??這次我們只更新 "FirstName" 字段試試末秃。
$ curl -i -X PUT http://localhost:8080/people/3 -d '{ "FirstName": "Tom" }'
??顯示如下
[{"id": 1,"firstname": "John","lastname": "Doe"},{"id": 2,"firstname": "Elvis","lastname": "Presley"},{"id": 3,"firstname": "Tom","lastname": "Sawyer"}]
刪除
??這次輪到刪除功能了
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
var db *gorm.DB
var err error
type Person struct {
ID uint `json:"id"`
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
}
func main() {
// NOTE: See we're using = to assign the global var
// instead of := which would assign it only in this function
db, err = gorm.Open("sqlite3", "./gorm.db")
if err != nil {
fmt.Println(err)
}
defer db.Close()
db.AutoMigrate(&Person{})
r := gin.Default()
r.GET("g/", GetProjects)
r.GET("/people/:id", GetPerson)
r.POST("/people", CreatePerson)
r.PUT("/people/:id", UpdatePerson)
r.DELETE("/people/:id", DeletePerson)
r.Run("g:8080")
}
func GetProjects(c *gin.Context) {
var people []Person
if err := db.Find(&people).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, people)
}
}
func GetPerson(c *gin.Context) {
id := c.Params.ByName("id")
var person Person
if err := db.Where("id = ?", id).First(&person).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, person)
}
}
func CreatePerson(c *gin.Context) {
var person Person
c.BindJSON(&person)
db.Create(&person)
c.JSON(200, person)
}
func UpdatePerson(c *gin.Context) {
var person Person
id := c.Params.ByName("id")
if err := db.Where("id = ?", id).First(&person).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
}
c.BindJSON(&person)
db.Save(&person)
c.JSON(200, person)
}
func DeletePerson(c *gin.Context) {
id := c.Params.ByName("id")
var person Person
d := db.Where("id = ?", id).Delete(&person)
fmt.Println(d)
c.JSON(200, gin.H{"id #" + id: "deleted"})
}
??我們用 curl 的 Delete 方法測試一下
$ curl -i -X DELETE http://localhost:8080/people/1
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Sat, 03 Dec 2016 00:32:40 GMT
Content-Length: 20
{"id #1":"deleted"}
??刷新瀏覽器概页,John Doe 這條記錄已經(jīng)刪掉了。
[{"id": 2,"firstname": "Elvis","lastname": "Presley"},{"id": 3,"firstname": "Tom","lastname": "Sawyer"}]