Golang 切片的结构或新手在构建 REST 时遇到麻烦

Golang slices of struct or newbie trouble building REST

需要你的帮助。 想要构建简单的 api 并遇到了一些问题。 我选择 gin and database/sql with postgres driver

package main

import (
    "database/sql"
    "fmt"

    "github.com/gin-gonic/gin"

    _ "github.com/lib/pq"
)

func main() {

    router := gin.Default()
    router.GET("/search/:text", SearchWord)
    router.Run(":8080")

}

我需要查询数据库并从这个请求中得到 json。

func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}

type Message struct {
    ticket_id int    `json:"ticket_id"`
    event     string `json:"event"`
}

func SearchWord(c *gin.Context) {
    word := c.Params.ByName("text")
    db, err := sql.Open("postgres", "host=8.8.8.8 user= password= dbname=sample")
    defer db.Close()
    checkErr(err)
    rows, err2 := db.Query("SELECT ticket_id,event FROM ...., word)
    checkErr(err)
    for rows.Next() {
        var ticket_id int
        var event string
        err = rows.Scan(&ticket_id, &event)
        checkErr(err)
        fmt.Printf("%d | %s \n\n", ticket_id, event)
    }

}

这个尾声很好用,但是当我需要制作时 json。 我需要制作一行的结构

type Message struct {
    ticket_id int    `json:"ticket_id"`
    event     string `json:"event"`
}

然后我需要创建 slice ,并附加每个 rows.Next() 循环,然后用 Json...

对浏览器进行回答
c.JSON(200, messages)

但是怎么做...不知道:(

免责声明:我是全新的

由于您 Scan 将列数据放入变量中,您应该能够使用它们的值初始化结构:

m := &Message{ticket_id: ticket_id, event: event}

您可以使用

初始化切片

s := make([]*Message, 0)

然后在实例化后附加每个消息结构:

s = append(s, m)


因为我不太熟悉 go 有几件事我不确定:

  • 在使用 rows.Scan 将数据从查询复制到您的 vars 后,初始化 Message 结构会按预期复制当前迭代值吗??

  • 如果有一种方法可以从查询中获取总行数,那么初始化静态长度数组而不是切片可能会更高效?

  • 我认为@inf 删除了关于将 Message 编组到 json 的答案可能需要解决,并且 Message 字段可能需要大写

从@inf 复制:

The names of the members of your struct need be capitalized so that they get exported and can be accessed.

type Message struct {
    Ticket_id int    `json:"ticket_id"`
    Event     string `json:"event"` }

我要在这里作弊并在此过程中解决一些问题:

首先:在程序启动时打开一次数据库连接池(而不是在每次请求时)。

其次:我们将使用 sqlx 来更轻松地将我们的数据库行编组到我们的结构中。

package main

var db *sqlx.DB

func main() {
    var err error
    // sqlx.Connect also checks that the connection works.
    // sql.Open only "establishes" a pool, but doesn't ping the DB.
    db, err = sqlx.Connect("postgres", "postgres:///...")
    if err != nil {
        log.Fatal(err)
    }

    router := gin.Default()
    router.GET("/search/:text", SearchWord)
    router.Run(":8080")

}

// in_another_file.go

type Message struct {
    TicketID int    `json:"ticket_id" db:"ticket_id"`
    Event     string `json:"event" db:"event"`
}

func SearchWord(c *gin.Context) {
    word := c.Params.ByName("text")
    // We create a slice of structs to marshal our rows into
    var messages []*Message{}
    // Our DB connection pool is safe to use concurrently from here
    err := db.Select(&messages, "SELECT ticket_id,event FROM ...., word)
    if err != nil {
        http.Error(c.Writer, err.Error(), 500)
        return
    }

    // Write it out using gin-gonic's JSON writer.
    c.JSON(200, messages)
}

我希望这很清楚。 sqlx 还负责为您调用 rows.Close(),否则会挂起连接。