So I just started learning the Go programming language and have spent hours on end looking at examples, references and so forth. As most of you would agree there is no better way to learn a language than to dive in and make something, which is what I am attempting to do at the moment. I am building a Restful web service. I have managed to get the basics running as well as inserting into db, registering routes etc. However for the past two days I have been struggling to implement application configurations/properties. It could just be that since I'm newbie my Go project architecture is all wrong hence why I am having such difficulty with this. Without further a due here is my project structure
src
server
database
dbaccess.go
dbcomm.go
handling
handler.go
handlercomm.go
models
config.go
response.go
user.go
routing
routes.go
main.go
Here is my config.go
package models
import (
"io/ioutil"
"encoding/json"
)
type Config struct {
Db map[string]string `json:"db"`
Server map[string]string `json:"server"`
}
func NewConfig(fname string) *Config{
data,err := ioutil.ReadFile(fname)
if err != nil{
panic(err)
}
config := Config{}
err = json.Unmarshal(data,&config)
if err != nil {
panic(err)
}
return config
This is my main
func main(){
args := os.Args[1:]
if len(args) == 0{
fmt.Println("********************\nMust specify a config file in args\n********************")
os.Exit(1)
}
config := models.NewConfig(args[0])
port := config.Server["PORT"]
router := routing.NewRouter()
fmt.Printf( "-------------------------------------------------\n"+
"Listening and Serving on Port %s\n"+
"-------------------------------------------------",port)
log.Fatal(http.ListenAndServe(":"+port,router))
}
And finally this is where my routes get mapped
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
var routes = []Route{
Route{
"signup",
"POST",
"/signup",
handling.PostSignUpUser,
},
Route{
"authenticate",
"POST",
"/login",
handling.PostLogin,
},
}
func NewRouter() *mux.Router{
router := mux.NewRouter().StrictSlash(true)
for _,route := range routes{
router.Methods(route.Method)
.Path(route.Pattern)
.Name(route.Name)
.Handler(route.HandlerFunc)
}
return router
}
So as you can see in my Main I initialise the relevant configurations from a file which is fine. But the issue is how would I go about using that same config object from main in the database package,since I will need to set Host,Ports etc ? I could parse the file again but I would prefer if I could share that one object from the start. Please point me in the right direction
What I would suggest is declaring a global variable in config.go
and initialize it using the init()
function. That way, you know that the variable will always be initialized when any package imports it. Here's some code:
package models
import (
"io/ioutil"
"encoding/json"
)
var (
Configuration Config
)
init() {
args := os.Args[1:]
if len(args) == 0{
fmt.Println("********************\nMust specify a config file in args\n********************")
os.Exit(1)
}
Configuration = NewConfig(args[0]) // configuration initialized here
}
type Config struct {
Db map[string]string `json:"db"`
Server map[string]string `json:"server"`
}
func NewConfig(fname string) *Config{
data,err := ioutil.ReadFile(fname)
if err != nil{
panic(err)
}
config := Config{}
err = json.Unmarshal(data,&config)
if err != nil {
panic(err)
}
return config
}
var()
is going to run before init()
, but init()
will run before the code in the package importing it. So if main.go
imports the models
package, then init()
in models
will run before any code inside main.go
and thus the variable Configuration
will be initialized before it is used.