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

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

Golang slices of struct or newbie trouble building REST

问题

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

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")

}

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 ....$1", 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"`
}

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

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

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")

}

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

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 ....$1, 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)
	}

}

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

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

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

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 来更轻松地将数据库行转换为结构体。

package main

import (
	"log"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/jmoiron/sqlx"
)

var db *sqlx.DB

func main() {
	var err error
	// sqlx.Connect 也会检查连接是否正常工作。
	// sql.Open 只是“建立”一个连接池,但不会 ping 数据库。
	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")
	// 我们创建一个结构体切片来将行转换为结构体
	var messages []*Message
	// 从这里开始,我们可以并发安全地使用数据库连接池
	err := db.Select(&messages, "SELECT ticket_id, event FROM ... WHERE ... = $1", word)
	if err != nil {
		http.Error(c.Writer, err.Error(), 500)
		return
	}

	// 使用 gin-gonic 的 JSON writer 输出结果
	c.JSON(200, messages)
}

希望这样清楚了。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 -->

package main

var db *sqlx.DB

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

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

}

// in_another_file.go

type Message struct {
    TicketID int    `json:&quot;ticket_id&quot; db:&quot;ticket_id&quot;`
    Event     string `json:&quot;event&quot; db:&quot;event&quot;`
}

func SearchWord(c *gin.Context) {
    word := c.Params.ByName(&quot;text&quot;)
    // 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(&amp;messages, &quot;SELECT ticket_id,event FROM ....$1, word)
    if err != nil {
        http.Error(c.Writer, err.Error(), 500)
        return
    }
    
    // Write it out using gin-gonic&#39;s JSON writer.
    c.JSON(200, messages)
}

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:

确定