如何为包含DB conn之类的应用程序包设置全局配置?

I've structured my application in two packages so far - main and app

In my main() I start my server:

func main() {
    router := app.CreateRouter(app.Routes())
    log.Fatal(http.ListenAndServe(":8080", router))
}

In app, I have a Config struct which has a method connectToDB:

type Config struct {
    DB *sql.DB
}

func (c *Config) connectToDB() {
    connectionString := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable", os.Getenv("DB_USERNAME"), os.Getenv("DB_PASSWORD"), os.Getenv("DB_NAME"))
    var err error
    c.DB, err = sql.Open("postgres", connectionString)
    if err != nil {
        log.Fatal(err)
    }
}

func init() {
    c := Config{}
    c.connectToDB()
}

However, I have various handlers and if I want to make use of Config.DB, how can I do that?

For example, in app.UserIndex, how can I get to Config.DB?

func UserIndex(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    fmt.Fprint(w, "test!
")
}

Now, one thing I can do is set a global variable, such as

var c Config

Then, I can access c.DB anywhere in package app. However, this feels bad..

You can make an App variable to keep there config and some other useful settings for it eg Http time-out

var (
      App struct {
           DB         *sql.DB
           Timeout time.Duration
           ...
      }
)

Then make methods on this structure. This way config will be incapsulated in application instance.

If you want to avoid globals, make your handlers structs instead of pure funcs:

type UserIndex struct {
    cfg Config
}

func (u UserIndex) ServeHTTP(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    fmt.Fprint(w, "test!
")
}

When setting up your routes, use UserIndex{c}.ServeHTTP instead of UserIndex.

The core library http package differentiates between a Handler type and a HandlerFunc for this reason. You appear to be using github.com/julienschmidt/httprouter, which doesn't make this distinction and doesn't provide an interface that matches its httprouter.Handle type, but you can still use a method on a struct to satisfy that type.