Golang切片的结构体或新手在构建REST时遇到的问题

huangapple go评论118阅读模式
英文:

Golang slices of struct or newbie trouble building REST

问题

我需要你的帮助。
我想构建一个简单的API,但遇到了一些问题。
我选择了gintpostgres驱动的database/sql。

  1. package main
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "github.com/gin-gonic/gin"
  6. _ "github.com/lib/pq"
  7. )
  8. func main() {
  9. router := gin.Default()
  10. router.GET("/search/:text", SearchWord)
  11. router.Run(":8080")
  12. }
  13. func checkErr(err error) {
  14. if err != nil {
  15. panic(err)
  16. }
  17. }
  18. type Message struct {
  19. ticket_id int `json:"ticket_id"`
  20. event string `json:"event"`
  21. }
  22. func SearchWord(c *gin.Context) {
  23. word := c.Params.ByName("text")
  24. db, err := sql.Open("postgres", "host=8.8.8.8 user= password= dbname=sample")
  25. defer db.Close()
  26. checkErr(err)
  27. rows, err2 := db.Query("SELECT ticket_id,event FROM ....$1", word)
  28. checkErr(err)
  29. for rows.Next() {
  30. var ticket_id int
  31. var event string
  32. err = rows.Scan(&ticket_id, &event)
  33. checkErr(err)
  34. fmt.Printf("%d | %s \n\n", ticket_id, event)
  35. }
  36. }

这段代码运行良好,但当我需要生成JSON时。
我需要创建一个行的结构体

  1. type Message struct {
  2. ticket_id int `json:"ticket_id"`
  3. event string `json:"event"`
  4. }

然后我需要创建一个切片,并在每个rows.Next()循环中追加,然后用JSON回复浏览器...

  1. c.JSON(200, messages)

但是如何做到这一点...不知道 Golang切片的结构体或新手在构建REST时遇到的问题

英文:

and need your help.
Wanted to build simple api and stuck with some problem.
I've choose gin and database/sql with postgres driver

  1. package main
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "github.com/gin-gonic/gin"
  6. _ "github.com/lib/pq"
  7. )
  8. func main() {
  9. router := gin.Default()
  10. router.GET("/search/:text", SearchWord)
  11. router.Run(":8080")
  12. }

I need to make query to DB and make json out of this request.

  1. func checkErr(err error) {
  2. if err != nil {
  3. panic(err)
  4. }
  5. }
  6. type Message struct {
  7. ticket_id int `json:"ticket_id"`
  8. event string `json:"event"`
  9. }
  10. func SearchWord(c *gin.Context) {
  11. word := c.Params.ByName("text")
  12. db, err := sql.Open("postgres", "host=8.8.8.8 user= password= dbname=sample")
  13. defer db.Close()
  14. checkErr(err)
  15. rows, err2 := db.Query("SELECT ticket_id,event FROM ....$1, word)
  16. checkErr(err)
  17. for rows.Next() {
  18. var ticket_id int
  19. var event string
  20. err = rows.Scan(&ticket_id, &event)
  21. checkErr(err)
  22. fmt.Printf("%d | %s \n\n", ticket_id, event)
  23. }
  24. }

This coda working nice, but when i need to make json.
I need to make struct of a row

  1. type Message struct {
  2. ticket_id int `json:"ticket_id"`
  3. event string `json:"event"`
  4. }

an then i need to create slice , and append every rows.Next() loop an than answer to browser with Json...

  1. c.JSON(200, messages)

But how to do that...don't know Golang切片的结构体或新手在构建REST时遇到的问题

答案1

得分: 1

免责声明:我对Go语言还不太熟悉。

由于你已经使用Scan将列数据扫描到变量中,你应该能够使用它们的值初始化一个结构体:

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

你可以使用以下方式初始化一个切片:

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

然后在实例化后,将每个消息结构体追加到切片中:

s = append(s, m)


由于我对Go语言不太熟悉,有几个问题我不太确定:

  • 在使用rows.Scan将数据从查询复制到变量后,初始化Message结构体是否按预期复制了当前迭代的值?

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

  • 我认为@inf删除的关于将Message转换为JSON的答案可能需要解决,并且Message字段可能需要大写。

从@inf复制过来的内容:

> 结构体成员的名称需要大写,这样它们才能被导出并访问。
>
> type Message struct {
> Ticket_id int json:"ticket_id"
> Event string json:"event" }

英文:

disclaimer: I am brand new to go

Since you Scanned your column data into your variables, you should be able to initialize a structure with their values:

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

You could initialize a slice with

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

And then append each of your message structs after instantiation:

s = append(s, m)


Because I'm not too familiar with go there are a couple things i'm not sure about:

  • after copying data from query to your vars using rows.Scan does initializing the Message struct copy the current iterations values as expected??

  • If there is a way to get the total number of rows from your query it might be slighlty more performant to initialize a static length array, instead of a slice?

  • I think @inf deleted answer about marshalling your Message to json down the line might need to be addressed, and Message field's might need to be capitalized

copied from @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" }

答案2

得分: 0

我稍微作弊一下,顺便修复一些问题:

首先,在程序启动时只需打开一次数据库连接池(而不是在每个请求中都打开)。

其次,我们将使用 sqlx 来更轻松地将数据库行转换为结构体。

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "github.com/gin-gonic/gin"
  6. "github.com/jmoiron/sqlx"
  7. )
  8. var db *sqlx.DB
  9. func main() {
  10. var err error
  11. // sqlx.Connect 也会检查连接是否正常工作。
  12. // sql.Open 只是“建立”一个连接池,但不会 ping 数据库。
  13. db, err = sqlx.Connect("postgres", "postgres:///...")
  14. if err != nil {
  15. log.Fatal(err)
  16. }
  17. router := gin.Default()
  18. router.GET("/search/:text", SearchWord)
  19. router.Run(":8080")
  20. }
  21. // in_another_file.go
  22. type Message struct {
  23. TicketID int `json:"ticket_id" db:"ticket_id"`
  24. Event string `json:"event" db:"event"`
  25. }
  26. func SearchWord(c *gin.Context) {
  27. word := c.Params.ByName("text")
  28. // 我们创建一个结构体切片来将行转换为结构体
  29. var messages []*Message
  30. // 从这里开始,我们可以并发安全地使用数据库连接池
  31. err := db.Select(&messages, "SELECT ticket_id, event FROM ... WHERE ... = $1", word)
  32. if err != nil {
  33. http.Error(c.Writer, err.Error(), 500)
  34. return
  35. }
  36. // 使用 gin-gonic 的 JSON writer 输出结果
  37. c.JSON(200, messages)
  38. }

希望这样清楚了。sqlx 还会为您调用 rows.Close(),否则连接会保持挂起状态。

英文:

I'm going to cheat a little here and fix a few things along the way:

First: open your database connection pool once at program start-up (and not on every request).

Second: we'll use sqlx to make it easier to marshal our database rows into our struct.

<!-- language: lang-go -->

  1. package main
  2. var db *sqlx.DB
  3. func main() {
  4. var err error
  5. // sqlx.Connect also checks that the connection works.
  6. // sql.Open only &quot;establishes&quot; a pool, but doesn&#39;t ping the DB.
  7. db, err = sqlx.Connect(&quot;postgres&quot;, &quot;postgres:///...&quot;)
  8. if err != nil {
  9. log.Fatal(err)
  10. }
  11. router := gin.Default()
  12. router.GET(&quot;/search/:text&quot;, SearchWord)
  13. router.Run(&quot;:8080&quot;)
  14. }
  15. // in_another_file.go
  16. type Message struct {
  17. TicketID int `json:&quot;ticket_id&quot; db:&quot;ticket_id&quot;`
  18. Event string `json:&quot;event&quot; db:&quot;event&quot;`
  19. }
  20. func SearchWord(c *gin.Context) {
  21. word := c.Params.ByName(&quot;text&quot;)
  22. // We create a slice of structs to marshal our rows into
  23. var messages []*Message{}
  24. // Our DB connection pool is safe to use concurrently from here
  25. err := db.Select(&amp;messages, &quot;SELECT ticket_id,event FROM ....$1, word)
  26. if err != nil {
  27. http.Error(c.Writer, err.Error(), 500)
  28. return
  29. }
  30. // Write it out using gin-gonic&#39;s JSON writer.
  31. c.JSON(200, messages)
  32. }

I hope that's clear. sqlx also takes care of calling rows.Close() for you, which will otherwise leave connections hanging.

huangapple
  • 本文由 发表于 2015年7月6日 00:10:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/31232316.html
匿名

发表评论

匿名网友

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

确定