J'utilise Gin, https://gin-gonic.github.io/gin/ , pour créer une API JSON RESTful simple avec Golang.
Les itinéraires sont configurés avec quelque chose comme ceci:
func testRouteHandler(c *gin.Context) {
// do smth
}
func main() {
router := gin.Default()
router.GET("/test", testRouteHandler)
router.Run(":8080")
}
Ma question est la suivante: comment puis-je transmettre un argument à la fonction testRouteHandler? Par exemple, une connexion à une base de données commune pourrait être quelque chose que l'on voudrait réutiliser entre les itinéraires.
Est-ce que le meilleur moyen d’avoir cela dans une variable globale? Ou y a-t-il un moyen dans Go de transmettre une variable supplémentaire à la fonction testRouteHandler? Existe-t-il des arguments optionnels pour les fonctions dans Go?
PS Je viens juste de commencer à apprendre Go, il pourrait donc être quelque chose d'évident qui me manque :)
En utilisant le lien que j'ai posté sur les commentaires, j'ai créé un exemple simple.
package main
import (
"log"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/mattn/go-sqlite3"
)
// ApiMiddleware will add the db connection to the context
func ApiMiddleware(db gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("databaseConn", db)
c.Next()
}
}
func main() {
r := gin.New()
// In this example, I'll open the db connection here...
// In your code you would probably do it somewhere else
db, err := gorm.Open("sqlite3", "./example.db")
if err != nil {
log.Fatal(err)
}
r.Use(ApiMiddleware(db))
r.GET("/api", func(c *gin.Context) {
// Don't forget type assertion when getting the connection from context.
dbConn, ok := c.MustGet("databaseConn").(gorm.DB)
if !ok {
// handle error here...
}
// do your thing here...
})
r.Run(":8080")
}
Ceci est juste un simple POC. Mais je crois que c'est un début… .. J'espère que ça aide.
J'éviterais de ranger les dépendances "d'application" (par exemple un pool de connexions de base de données) dans un contexte de requête. Les deux options les plus faciles sont:
*sql.DB
est thread-safe.gin.HandlerFunc
par exemple.
// SomeHandler returns a `func(*gin.Context)` to satisfy Gin's router methods
// db could turn into an 'Env' struct that encapsulates all of your
// app dependencies - e.g. DB, logger, env vars, etc.
func SomeHandler(db *sql.DB) gin.HandlerFunc {
fn := func(c *gin.Context) {
// Your handler code goes in here - e.g.
rows, err := db.Query(...)
c.String(200, results)
}
return gin.HandlerFunc(fn)
}
func main() {
db, err := sql.Open(...)
// handle the error
router := gin.Default()
router.GET("/test", SomeHandler(db))
router.Run(":8080")
}
En retard à la fête, voici ma proposition. Incapsulez des méthodes dans l'objet avec des variables privées/publiques:
package main
import (
"log"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/mattn/go-sqlite3"
)
type HandlerA struct {
Db gorm.DB
}
func (this *HandlerA) Get(c *gin.Context) {
log.Info("[%#f]", this.Db)
// do your thing here...
}
func main() {
r := gin.New()
// Init, should be separate, but it's ok for this sample:
db, err := gorm.Open("sqlite3", "./example.db")
if err != nil {
log.Fatal(err)
}
Obj := new(HandlerA)
Obj.Db = db // Or init inside Object
r := gin.New()
Group := r.Group("api/v1/")
{
Group.GET("/storage", Obj.Get)
}
r.Run(":8080")
}
Bon, je vous ai donné un exemple simple. Ça devrait marcher. Vous pouvez l'étendre selon vos besoins
func main() {
router := gin.Default()
router.GET("/test/:id/:name", testRouteHandler)
router.Run(":8080")
}
func testRouteHandler(c *gin.Context) {
id := c.Params.ByName("id")
name := c.Params.ByName("name")
}
Vous devez maintenant appeler votre gestionnaire comme indiqué ci-dessous http: // localhost: 8080/test/1/myname