web-dev-qa-db-fra.com

Comment passer des arguments aux gestionnaires de routeurs de Golang en utilisant le framework web Gin?

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

13
Niklas9

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.

13
rcmgleite

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:

  1. Faites-en un global. Cela convient pour les projets plus petits et *sql.DB est thread-safe.
  2. Transmettez-le explicitement dans une fermeture de sorte que le type de retour satisfasse 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")
}
11
elithrar

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")
}
1
wildneuro

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

0
deepak