0

I am trying to connect Go application with MongoDB server while running the database using docker.

I'm able to connect to the DB using the shell and perform different actions. However, the Go app fails when connecting to the DB. I'm using mgo driver and below is the code in use where am trying to implement a db middleware that can be used by all routes:

middleware code:

package db

import (
    "net/http"
    "os"

    "github.com/gorilla/context"
    "github.com/urfave/negroni"
    mgo "gopkg.in/mgo.v2"
)

const key = "dbkey"

func GetDb(r *http.Request) *mgo.Database {
    if rv := context.Get(r, key); rv != nil {
        return rv.(*mgo.Database)
    }
    return nil
}

func SetDb(r *http.Request, val *mgo.Database) {
    context.Set(r, key, val)
}

func MongoMiddleware() negroni.HandlerFunc {
    database := os.Getenv("DB_NAME")
    session, err := mgo.Dial("127.0.0.1:27017")

    if err != nil {
        println(err) // error message below
    }

    return negroni.HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
        reqSession := session.Clone()
        defer reqSession.Close()
        db := reqSession.DB(database)
        SetDb(r, db)
        next(rw, r)
    })
}

the error am getting is :

panic: runtime error: invalid memory address or nil pointer dereference

route and main package code:

package main

import (
    gmux "github.com/gorilla/mux"
    "github.com/urfave/negroni"
    "github.com/mypro/db"
    "github.com/mypro/hub"
)

func main() {
    router := gmux.NewRouter()

    router.HandleFunc("/name", hub.Create).
        Methods("GET")

    n := negroni.Classic()
    n.Use(db.MongoMiddleware())
    n.UseHandler(router)
    n.Run(":9000")
}

method that consume the db middleware to find a collection:

type Name struct {
    Id   bson.ObjectId `bson:"_id"`
    Name string        `bson:"name"`
}

func Create(w http.ResponseWriter, r *http.Request) {
    var aName Name
    db := db.GetDb(r)
    names := db.C("x")

    err := names.Find(bson.M{"name": "sam"}).One(&aName)
    if err != nil {
        log.Print(err)
    }
    fmt.Println(&aName)
    json.NewEncoder(w).Encode(&aName)
}
user3462064
  • 455
  • 2
  • 6
  • 24
  • 1
    Give us more context. That isn't an error that will be caught. Somewhere you are using an invalid memory address or nil pointer dereference. – Gavin Jul 14 '17 at 14:10
  • I added more context – user3462064 Jul 14 '17 at 18:28
  • 2
    The only place I see potential for your error is using your `db` var in the `Create` method before checking it for nil. For future reference - it's not good practice to pass around a db connection in the request context. [Here](https://stackoverflow.com/a/43961405/6069012)'s a simple example I've given for a better approach. – Gavin Jul 14 '17 at 19:44
  • You're correct db is nil, but i don't know why GetDb return nil – user3462064 Jul 14 '17 at 19:50
  • This is where a debugger comes in really nice. Check your `val` in `SetDb` before setting it and `rv` in `GetDb` after getting it; that might give you some insight as to what's going on. – Gavin Jul 14 '17 at 19:57
  • SetDb seems to set the value correctly but it's nil in GetDb – user3462064 Jul 14 '17 at 20:19
  • This is really bad practice. You are initializing a new session with every requests that comes in because you've wrapped it as middleware... even without the issue you currently have, you're going to run into plenty other ones especially at scale. You should reimplement and use this as a guide https://stackoverflow.com/questions/26574594/best-practice-to-maintain-a-mgo-session, as a side note. Try connecting to mongo with `session, err := mgo.Dial("127.0.0.1:27017")` in another file.. for example https://play.golang.org/p/H9lHOA5qu- if it fails still then check that mongod is running. – reticentroot Jul 15 '17 at 17:15

0 Answers0