【翻译】基于Go框架Gin开发RESTFul API

原创文章,转载请注明: 转载自勤奋的小青蛙
本文链接地址: 【翻译】基于Go框架Gin开发RESTFul API

参考:How to create a basic RESTful API in Go

像任何语言一样,可以使用Golang快速编写基本的RESTful API。在此示例中,数据可以通过JSON格式的标准HTTP方法(GET,POST,PUT&DELETE)访问。数据行将存储在SQLite数据库中。

我们本文演示一个简单的用户管理 RESTFul API

基本框架

路由:

数据表:

  • id — integer & auto-increment
  • firstname — varchar(255)
  • lastname — varchar(255)

使用Gin做路由转发

我们将使用Gin,这是一个微框架路由。它易于使用并且路由性能很牛x。

首先是获取gin包

go get github.com/gin-gonic/gin

好的,我们开始编码!首先在一个新的“main.go”文件中,我们称之为我们的库。

package main

import (
    "strconv"
    
     "github.com/gin-gonic/gin"
)

其次,我们声明User结构:

type Users struct {
    Id        int    `gorm:"AUTO_INCREMENT" form:"id" json:"id"`
    Firstname string `gorm:"not null" form:"firstname" json:"firstname"`
    Lastname  string `gorm:"not null" form:"lastname" json:"lastname"`
}

“gorm”参数将在以后使用数据库连接时用到...

最后,在main()函数中,我们在一个组中调用我们的路由:

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

    v1 := r.Group("api/v1")
    {
        v1.POST("/users", PostUser)
        v1.GET("/users", GetUsers)
        v1.GET("/users/:id", GetUser)
        v1.PUT("/users/:id", UpdateUser)
        v1.DELETE("/users/:id", DeleteUser)
    }

    r.Run(":8080")
}

声明完路由,接下来我们要做的就是完成路由对应的处理函数:

func PostUser(c *gin.Context) {
    // The futur code…
}

func GetUsers(c *gin.Context) {
    var users = []Users{
        Users{Id: 1, Firstname: "Oliver", Lastname: "Queen"},
        Users{Id: 2, Firstname: "Malcom", Lastname: "Merlyn"},
    }

    c.JSON(200, users)

    // curl -i http://localhost:8080/api/v1/users
}

func GetUser(c *gin.Context) {
    id := c.Params.ByName("id")
    user_id, _ := strconv.ParseInt(id, 0, 64)

    if user_id == 1 {
        content := gin.H{"id": user_id, "firstname": "Oliver", "lastname": "Queen"}
        c.JSON(200, content)
    } else if user_id == 2 {
        content := gin.H{"id": user_id, "firstname": "Malcom", "lastname": "Merlyn"}
        c.JSON(200, content)
    } else {
        content := gin.H{"error": "user with id#" + id + " not found"}
        c.JSON(404, content)
    }

    // curl -i http://localhost:8080/api/v1/users/1
}

func UpdateUser(c *gin.Context) {
    // The futur code…
}

func DeleteUser(c *gin.Context) {
    // The futur code…
}

写到这里,我们的API服务器已经可以使用了,我们运行起来:

go run main.go

正如你所看到的,为了显示用户,我们采用GET方式获取User列表,返回假的数据:

[{"id":1,"firstname":"Oliver","lastname":"Queen"},{"id":2,"firstname":"Malcom","lastname":"Merlyn"}]

如果只是查找某个用户:

{"firstname":"Oliver","id":1,"lastname":"Queen"}

将数据存入到SQLite

go get github.com/jinzhu/gorm

使用Gorm,我们将使用一个SQLite数据库。您也可以使用MySQL(和MariaDB),Postgres和FoundationDB数据库。

go get github.com/mattn/go-sqlite3

如果您忘记导入新的库文件(并且我们不需要“strconv”库),您的编译器将会报错。

import (
    "github.com/gin-gonic/gin"
    "github.com/jinzhu/gorm"
    _ "github.com/mattn/go-sqlite3"
)

不需要手动创建数据库文件和用户表,Gorm可以帮你实现。 ☺

func InitDb() *gorm.DB {
    // Openning file
    db, err := gorm.Open("sqlite3", "./data.db")
    db.LogMode(true)
    // Error
    if err != nil {
        panic(err)
    }
    // Creating the table
    if !db.HasTable(&Users{}) {
        db.CreateTable(&Users{})
        db.Set("gorm:table_options", "ENGINE=InnoDB").CreateTable(&Users{})
    }

    return db
}

在下次重新启动您的服务器时,我们将会使用data.db数据库,并且根据User字段创建好了User表。

那么下面就讲SQLite针对User的CRUD操作。

新增用户

func PostUser(c *gin.Context) {
    db := InitDb()
    defer db.Close()

    var user Users
    c.Bind(&user)

    if user.Firstname != "" && user.Lastname != "" {
        // INSERT INTO "users" (name) VALUES (user.Name);
        db.Create(&user)
        // Display error
        c.JSON(201, gin.H{"success": user})
    } else {
        // Display error
        c.JSON(422, gin.H{"error": "Fields are empty"})
    }

    // curl -i -X POST -H "Content-Type: application/json" -d "{ \"firstname\": \"Thea\", \"lastname\": \"Queen\" }" http://localhost:8080/api/v1/users
}

在curl命令之后,data.db被创建,然后返回结果如下:

HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
{"success":{"id":1,"firstname":"Thea","lastname":"Queen"}}

获取所有用户

func GetUsers(c *gin.Context) {
    // Connection to the database
    db := InitDb()
    // Close connection database
    defer db.Close()

    var users []Users
    // SELECT * FROM users
    db.Find(&users)

    // Display JSON result
    c.JSON(200, users)

    // curl -i http://localhost:8080/api/v1/users
}

获取结果:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
[{"id":1,"firstname":"Thea","lastname":"Queen"}]

获取指定User

func GetUser(c *gin.Context) {
    // Connection to the database
    db := InitDb()
    // Close connection database
    defer db.Close()

    id := c.Params.ByName("id")
    var user Users
    // SELECT * FROM users WHERE id = 1;
    db.First(&user, id)

    if user.Id != 0 {
        // Display JSON result
        c.JSON(200, user)
    } else {
        // Display JSON error
        c.JSON(404, gin.H{"error": "User not found"})
    }

    // curl -i http://localhost:8080/api/v1/users/1
}

返回结果:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":1,"firstname":"Thea","lastname":"Queen"}

更新用户

func UpdateUser(c *gin.Context) {
    // Connection to the database
    db := InitDb()
    // Close connection database
    defer db.Close()

    // Get id user
    id := c.Params.ByName("id")
    var user Users
    // SELECT * FROM users WHERE id = 1;
    db.First(&user, id)

    if user.Firstname != "" && user.Lastname != "" {

        if user.Id != 0 {
            var newUser Users
            c.Bind(&newUser)

            result := Users{
                Id:        user.Id,
                Firstname: newUser.Firstname,
                Lastname:  newUser.Lastname,
            }

            // UPDATE users SET firstname='newUser.Firstname', lastname='newUser.Lastname' WHERE id = user.Id;
            db.Save(&result)
            // Display modified data in JSON message "success"
            c.JSON(200, gin.H{"success": result})
        } else {
            // Display JSON error
            c.JSON(404, gin.H{"error": "User not found"})
        }

    } else {
        // Display JSON error
        c.JSON(422, gin.H{"error": "Fields are empty"})
    }

    // curl -i -X PUT -H "Content-Type: application/json" -d "{ \"firstname\": \"Thea\", \"lastname\": \"Merlyn\" }" http://localhost:8080/api/v1/users/1
}

返回结果:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"success":{"id":1,"firstname":"Thea","lastname":"Merlyn"}}

删除用户

func DeleteUser(c *gin.Context) {
    // Connection to the database
    db := InitDb()
    // Close connection database
    defer db.Close()

    // Get id user
    id := c.Params.ByName("id")
    var user Users
    // SELECT * FROM users WHERE id = 1;
    db.First(&user, id)

    if user.Id != 0 {
        // DELETE FROM users WHERE id = user.Id
        db.Delete(&user)
        // Display JSON result
        c.JSON(200, gin.H{"success": "User #" + id + " deleted"})
    } else {
        // Display JSON error
        c.JSON(404, gin.H{"error": "User not found"})
    }

    // curl -i -X DELETE http://localhost:8080/api/v1/users/1
}

返回结果:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"success":"User #1 deleted"}

CORS

您可以直接在路由中使用CORS。

c.Writer.Header().Add("Access-Control-Allow-Origin", "*")
c.Next()

或者在全球范围内使用“gin.HandlerFunc”功能的自定义中间件:

func Cors() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Writer.Header().Add("Access-Control-Allow-Origin", "*")
        c.Next()
    }
}

在路由调用之前传入该中间件:

r.Use(Cors())

如果您没有激活CORS,Chrome将会收到与此类似的消息错误:

XMLHttpRequest cannot load http://localhost:8080/api/v1/users. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:8081' is therefore not allowed access.

AJAX OPTIONS

如果您使用Javacript和CORS使用“XMLHttpRequest”或“Fetch”,则需要使用“OPTIONS”作为POST,PUT,DELETE请求。

首先,您必须添加2条路由。

v1.OPTIONS("/users", OptionsUser)      // POST
v1.OPTIONS("/users/:id", OptionsUser)  // PUT, DELETE

并声明“OptionsUser”函数:

func OptionsUser(c *gin.Context) {
    c.Writer.Header().Set("Access-Control-Allow-Methods", "DELETE,POST, PUT")
    c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type")
    c.Next()
}

如果您不使用此方法,您将会遇到与Chrome相似的消息错误:

XMLHttpRequest cannot load http://localhost:8080/api/v1/users/1. Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:8081' is therefore not allowed access. The response had HTTP status code 404.

事实上,浏览器找不到该OPTIONS链接:

http://localhost:8080/api/v1/users/1

总结

按照上述代码我们便实现了一个简单具有基本CRUD功能的RESTful API的例子。你可以看到,数据结构体在Golang中是非常重要的,特别是当你操纵一些Json数据时。

源码下载地址:Golang Gin RESTFul API with SQLite

更多参考信息:

原创文章,转载请注明: 转载自勤奋的小青蛙
本文链接地址: 【翻译】基于Go框架Gin开发RESTFul API

文章的脚注信息由WordPress的wp-posturl插件自动生成



|2|left
打赏

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: