2016-02-27 11 views
5

私はGoを試し始めました。ノードで書かれたAPIサーバを再実装しようとしています。GoとGin:データベースコンテキストの構造体を渡しますか?

私はジンミドルウェアとしてデータベースコンテキストを回避するために依存関係注入を使用しようとするとハードルを打ちました。

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

モデル/ 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 
} 

モデル/ 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 
     } 
} 

これまでのところ、私はこのようにそれを設定しましただから上のすべてで、私はミドルウェアのようにアクセスできるようにモデルのDataSourceを渡したい:

デシベルはちょうど空のオブジェクトである

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

public.go公開/私は(プラグインでWebstormを使用して)デバッガで検査したとき、私は public\public.go:10: db.GetVotePack undefined (type interface {} is interface with no methods)

を取得しますが。私は良いことをしようとしているとグローバル変数の使用を避ける

答えて

6

値はタイプinterface{}のすべてなので、dbは、それが戻ってその型に変換されるまで種類*DBからメソッドを呼び出すことはできません。

安全な方法:

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

Effective Goは、この上のセクションがあります。

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

少ない安全な方法、context.Keys["DB"]あればパニックになるタイプ*DBの値ではありません。

+0

パーフェクト、それはそれを解決するようだ。 –

+0

これは問題を解決しますが、私にとっては非常に悪いデザインのようです。インターフェース{}構造体を汎用コンテキストに置く人に頼ることは、強く型付けされた適切なデザインのようには見えません。私は間違いの大部分は、ジンがインターフェイスではなくhandleメソッドのための関数を期待しているからだと思う。 –

+0

@SnoProblem Contextを通してデータベース接続を渡すのは良い方法ですか? &他の方法はありますか? –

1

あなたは有用なものにインターフェイス(db:= context.Keys ["DB"])を変換するには、アサーションを入力する必要があります。例えば、この記事を参照してください:context.Keysconvert interface{} to int in Golang

関連する問題