2015-11-11 13 views
5

Al momento, provo a creare un piccolo progetto Web utilizzando Vai per la gestione dei dati sul server.Vai a utilizzare il router mux - Come passare il mio DB ai miei gestori

Cerco di passare la mia connessione al database al mio HandlerFunc (tions) ma non funziona come previsto. Sono abbastanza nuovo per Golang, quindi forse non ho capito alcuni principi di base di questo lang.

mio func principale appare così:

func main() { 

    db, err := config.NewDB("username:[email protected]/databasename?charset=utf8&parseTime=True") 
    if err != nil { 
     log.Panic(err) 
    } 
    env := &config.Env{DB: db} 

    router := NewRouter(env) 
    log.Fatal(http.ListenAndServe(":8080", router)) 
} 

mio router:

func NewRouter(env *config.Env) *mux.Router { 
    router := mux.NewRouter().StrictSlash(true) 
    for _, route := range routes { 
     var handler http.Handler 

     handler = route.HandlerFunc 
     handler = Logger(handler, route.Name) 

     router. 
      Methods(route.Method). 
      Path(route.Pattern). 
      Name(route.Name). 
      Handler(handler) 
    } 
    return router 
} 

ei miei percorsi:

type Route struct { 
    Name  string 
    Method  string 
    Pattern  string 
    HandlerFunc http.HandlerFunc 
} 

type Routes []Route 

var routes = Routes{ 
    Route{ 
     "Index", 
     "GET", 
     "/", 
     controller.Index, 
    }, 
    Route{ 
     "Show", 
     "GET", 
     "/todos/{todoId}", 
     controller.TodoShow, 
    }, 
    Route{ 
     "Create", 
     "POST", 
     "/todos", 
     controller.TodoCreate, 
    }, 
} 

Così - come posso passare la mia "ENV" (o env.DB) ai miei FuncHandlers? Ho provato molte cose, ma nessuna ha funzionato.

risposta

11

Sono disponibili tre opzioni:

  1. Fai il pool di connessione al database a livello globale , così da non doverlo passare. sql.DB è sicuro per l'accesso simultaneo e questo è l'approccio più semplice. Il rovescio della medaglia è che rende i test più difficili e offusca "dove" proviene la piscina - ad es.

    var db *sql.DB 
    
    func main() { 
        var err error 
        db, err = sql.Open(...) 
        // Now accessible globally, no need to pass it around 
        // ... 
    } 
    
  2. avvolgere i gestori in una chiusura, il che lo rende accessibile al gestore interiore. Avrai bisogno di adattare questo per la vostra gamma-over-percorsi di avvicinamento, il che è un po 'ottusa IMO, e rende più difficile per vedere che esistono percorsi, ma sto divagando, ad esempio:

    func SomeHandler(db *sql.DB) http.HandlerFunc { 
        fn := func(w http.ResponseWriter, r *http.Request) { 
         res, err := db.GetThings() 
         // etc. 
        } 
    
        return http.HandlerFunc(fn) 
    } 
    
    func main() { 
        db, err := sql.Open(...) 
        http.HandleFunc("/some-route", SomeHandler(db)) 
        // etc. 
    } 
    
  3. Creare un tipo di gestore personalizzato che accetta un gestore - es

    type AppHandler struct { 
        Handler func(env *config.Env, w http.ResponseWriter, r *http.Request) 
        Env *config.Env 
    
    // ServeHTTP allows your type to satisfy the http.Handler interface. 
    func (ah *AppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 
        ah.Handler(ah.Env, w, r) 
    } 
    
    func SomeHandler(env *config.Env, w http.ResponseWriter, r *http.Request) { 
        res, err := env.DB.GetThings() 
        // etc. 
    } 
    

Si noti che (senza vergogna!) Ho written about the last approach in detail, e Alex Edwards ha un excellent blog post su approcci per l'accesso a piscine DB nei programmi di Go pure.

L'unico consiglio rigoroso che posso dare è che si dovrebbe evitare di passare il pool DB in un contesto di richiesta, che è inefficiente e non corretto (i contesti di richiesta sono per oggetti temporanei, per richiesta).

+1

Grazie mille, Ho già dato un'occhiata al post di Alex Edwards e ho cercato di implementare la sua soluzione di chiusura (usando il suo esempio su https: //gist.github.it/alexedwards/5cd712192b4831058b21) Ora, l'ho cambiato e uso una variabile globale nel mio pacchetto di modelli e sta funzionando. Non sono ancora sicuro se sia la soluzione migliore per il mio progetto, ma per il momento si adatta alle mie esigenze. – Newbie

0

È sempre possibile definire "env" come global variable.

Ma prima che tutti mi odino, questa non è una buona soluzione! Dovresti creare un pacchetto che incapsuli l'accesso al tuo database con una funzione pubblica che indichi il tuo intento preciso.

Qualcosa sulla falsariga di

Package db 

var config .... 

func ShowTodos(params ...) result { 
    your database access code here.... 
} 

e dalla funzione di router di accesso con

db.ShowTodos(...)