Go and Gin: Passing a structure for a database context?

I just started checking Go, and I'm looking to reimplement the API server written in node with it.

I ran into an obstacle trying to use dependency injection to pass the database context as gin middleware. So far I have installed this as:

main.go:

package main import ( "fmt" "runtime" "log" "github.com/gin-gonic/gin" "votesforschools.com/api/public" "votesforschools.com/api/models" ) type DB struct { models.DataStore } func main() { ConfigRuntime() ConfigServer() } func Database(connectionString string) gin.HandlerFunc { dbInstance, err := models.NewDB(connectionString) if err != nil { log.Panic(err) } db := &DB{dbInstance} return func(c *gin.Context) { c.Set("DB", db) c.Next() } } func ConfigRuntime() { nuCPU := runtime.NumCPU() runtime.GOMAXPROCS(nuCPU) fmt.Printf("Running with %d CPUs\n", nuCPU) } func ConfigServer() { gin.SetMode(gin.ReleaseMode) router := gin.New() router.Use(Database("<connectionstring>")) router.GET("/public/current-vote-pack", public.GetCurrentVotePack) router.Run(":1000") } 

models / db.go

 package models import ( "database/sql" _ "github.com/go-sql-driver/mysql" ) type DataStore interface { GetVotePack(id string) (*VotePack, error) } type DB struct { *sql.DB } func NewDB(dataSource string) (*DB, error) { db, err := sql.Open("mysql", dataSource) if err != nil { return nil, err } if err = db.Ping(); err != nil { return nil, err } return &DB{db}, nil } 

models / votepack.go

 package models import ( "time" "database/sql" ) type VotePack struct { id string question string description string startDate time.Time endDate time.Time thankYou string curriculum []string } func (db *DB) GetVotePack(id string) (*VotePack, error) { var votePack *VotePack err := db.QueryRow( "SELECT id, question, description, start_date AS startDate, end_date AS endDate, thank_you AS thankYou, curriculum WHERE id = ?", id).Scan( &votePack.id, &votePack.question, &votePack.description, &votePack.startDate, &votePack.endDate, &votePack.thankYou, &votePack.curriculum) switch { case err == sql.ErrNoRows: return nil, err case err != nil: return nil, err default: return votePack, nil } } 

So, with all of the above, I want to pass models.DataSource as middleware so that it can be obtained as follows:

open / public.go

 package public import ( "github.com/gin-gonic/gin" ) func GetCurrentVotePack(context *gin.Context) { db := context.Keys["DB"] votePack, err := db.GetVotePack("c5039ecd-e774-4c19-a2b9-600c2134784d") if err != nil{ context.String(404, "Votepack Not Found") } context.JSON(200, votePack) } 

However, I get public\public.go:10: db.GetVotePack undefined (type interface {} is interface with no methods)

When I check in the debugger (using Webstorm with the plugin), db is just an empty object. I try to be good and avoid using global variables

+5
source share
2 answers

The values โ€‹โ€‹inside context.Keys are interface{} types, so db will not be able to call methods from *DB type until it is converted back to this type.

Safe way:

 db, ok := context.Keys["DB"].(*DB) if !ok { //Handle case of no *DB instance } // db is now a *DB value 

A less secure way to panic if context.Keys["DB"] not a *DB type value:

 db := context.Keys["DB"].(*DB) // db is now a *DB value 

The effective way contains a section about this.

+6
source

You will need a type statement to convert the interface (db: = context.Keys ["DB"]) into something useful. See For example, the message: convert interface {} to int in Golang

+1
source

Source: https://habr.com/ru/post/1244015/


All Articles