markhorrocks
markhorrocks

Reputation: 1418

How to pass vars to chi router in Golang

I'm writing a web app using chi router and have global vars for the database connection string and gorilla sessions mysqlstore. I want to pass these to the chi mount function instead of using global vars but can't figure out how to do it.

Here is my code, redacted for brevity.

var dBSource string

var store *mysqlstore.MySQLStore

func main() {

  var err error

  dBSource = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8", dbUser, dbPass, dbHost, dbPort, dbName)

  store, err = mysqlstore.NewMySQLStore(endpoint, tableName, path, maxAge, codecs)

  defer store.Close()

  r := chi.NewRouter()

  r.Mount("/users", usersResource{}.Routes())
}

type usersResource struct{}

func (rs usersResource) Routes() chi.Router {
    r := chi.NewRouter()

    r.Get("/", rs.List)

    return r
}

func (rs usersResource) List(w http.ResponseWriter, r *http.Request) {

    session, err := store.Get(r, "session-data")

    db, err := sql.Open("mysql", dBSource)
}

Upvotes: 1

Views: 2060

Answers (2)

markhorrocks
markhorrocks

Reputation: 1418

For completeness, here is how I implemented the accepted solution. Hopefully, it may save another newbie a bunch of time.

type appResource struct {
    tmpl  *template.Template // net/http
    store *mysqlstore.MySQLStore
    db    *sql.DB // database/sql
}

func newAppResource(store *mysqlstore.MySQLStore, db *sql.DB, tmpl *template.Template) *appResource {
    return &appResource{
        tmpl:  tmpl,
        store: store,
        db:    db,
    }
}

func main() {

  var err error

  err = godotenv.Load()
  if err != nil {
     log.Fatal("Error loading .env file")
  }

  dbUser := os.Getenv("dbUser")
  dbName := os.Getenv("dbName")
  dbPass := os.Getenv("dbPass")
  dbHost := os.Getenv("dbHost")
  dbPort := os.Getenv("dbPort")

  dBSource := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8", dbUser, dbPass, dbHost, dbPort, dbName)

  db, err := sql.Open("mysql", dBSource)
  if err != nil {
     log.Fatal(err)
  }

  sessionKey := os.Getenv("sessionKey")

  endpoint := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true&loc=Local", dbUser, dbPass, dbHost, dbPort, dbName)
  tableName := "sessions"
  path := "/"
  maxAge := 3600
  codecs := []byte(sessionKey)

  store, err := mysqlstore.NewMySQLStore(endpoint, tableName, path, maxAge, codecs)
  if err != nil {
    log.Println("SESSIONS STORE error")
    log.Fatal(err)
  }

  r := chi.NewRouter()

  r.Get("/", rs.adminIndex)

  r.Mount("/users", rs.userRoutes())

  httpPort := os.Getenv("httpPort")

  http.ListenAndServe(httpPort, r)
}

func (rs *appResource) adminIndex(w http.ResponseWriter, r *http.Request) {
    session, err := rs.store.Get(r, "admin-data")
    if err != nil {
        log.Fatal(err)
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    var flash map[string]interface{}

    if flashes := session.Flashes(); len(flashes) > 0 {
        v := map[string]interface{}{
            "FlashedMessages": session.Flashes(),
        }
        flash = v
    }

    if err := rs.tmpl.ExecuteTemplate(w, "admin-index", flash); err != nil {
        log.Println(err.Error())
        http.Error(w, http.StatusText(500), 500)
    }
}

Upvotes: 1

Billy Yuan
Billy Yuan

Reputation: 1295

Usually, we do that this way.


func main() {

......
  r := chi.NewRouter()

  // keep db connection alive.
  db, err := sql.Open("mysql", dBSource)

  ur := NewUserResource(store, db)

  r.Mount("/users", ur.Routes())
}

type usersResource struct{
  store *mysqlstore.MySQLStore
// and more...
  db *YourDB
}

// new function to pass global var
func newUserResource(store *mysqlstore.MySQLStore, db *YourDB) *usersResource{
  return &usersResource {
    store: store,
    db: db,
  }
}

func (rs *usersResource) List(w http.ResponseWriter, r *http.Request) {
    // don't use global var
    session, err := ur.store.Get(r, "session-data")

    ur.db.GetWhatever()

}

Upvotes: 6

Related Questions