# Go Cheatsheet - Read Config File

## Read Config File

### Json

If your config file only contains a few of fields, and you don't want to install external modules, the easiest way is just using the json file.

Suppose we have a config file like below:
```json
{
    "host": "127.0.0.1",
    "port": 8080,
    "redis": {
        "keyprefix": "golang",
        "server": "127.0.0.1:6079"
    }
}
```

Then we can define our structs and parse it in Go:
```go
type rediscfg struct {
	KeyPrefix string `json:"keyprefix"`
	Server    string `json:"server"`
}

type config struct {
	Host  string   `json:"host"`
	Port  int      `json:"port"`
	Redis rediscfg `json:"redis"`
}

func main() {
	content, _ := ioutil.ReadFile("./config.json")
	var cfg config
	json.Unmarshal(content, &cfg)
}
```

### Read Json with Viper

First we need to install `viper`: 
```bash
$ go get github.com/spf13/viper
```

Then read it with Viper
```go
import "github.com/spf13/viper"

// need to define mapstructure tag which Viper is using
type rediscfg struct {
	KeyPrefix string `json:"keyprefix" mapstructure:"keyprefix"`
	Server    string `json:"server"    mapstructure:"server"`
}

type config struct {
	Host  string   `json:"host"  mapstructure:"host"`
	Port  int      `json:"port"  mapstructure:"port"`
	Redis rediscfg `json:"redis" mapstructure:"redis"`
}

func main() {
    viper.SetConfigFile("./config.json")
	var cfg config
	if err := viper.ReadInConfig(); err != nil {
		log.Fatalln("Failed to read config file")
	}
	// use the unmarshal way
	viper.Unmarshal(&cfg)
}
```

An easier way is just use `viper.Get` function, which you don't even need to define the `config` struct.

```go
// we don't need to predefine the config struct here

func main() {
	viper.SetConfigFile("./config.json")
	var cfg config
	if err := viper.ReadInConfig(); err != nil {
		log.Fatalln("Failed to read config file")
	}
	fmt.Println("Host:", viper.GetString("host"))
	fmt.Println("Redis Server:", viper.GetString("redis.server"))
}
```

### Use YAML

With viper we can also use the `yaml` format. Suppose we have the yaml file like this:
```yaml
host: 127.0.0.1
port: 8080

redis:
  keyprefix: golang
  server: 127.0.0.1:6379
```

The beauty is we only need to change the config file path:

Without defining the `config` struct:
```go
func main() {
    // only need to change the config file name/path here
	viper.SetConfigFile("./config.yaml")
	var cfg config
	if err := viper.ReadInConfig(); err != nil {
		log.Fatalln("Failed to read config file")
	}
	fmt.Println("Host:", viper.GetString("host"))
	fmt.Println("Redis Server:", viper.GetString("redis.server"))
}
```

With defining the `config` struct:
```go
import "github.com/spf13/viper"

// need to define mapstructure tag which Viper is using
type rediscfg struct {
	KeyPrefix string `json:"keyprefix" mapstructure:"keyprefix"`
	Server    string `json:"server"    mapstructure:"server"`
}

type config struct {
	Host  string   `json:"host"  mapstructure:"host"`
	Port  int      `json:"port"  mapstructure:"port"`
	Redis rediscfg `json:"redis" mapstructure:"redis"`
}

func main() {
    // only need to change the config file name/path here
    viper.SetConfigFile("./config.yaml")
	var cfg config
	if err := viper.ReadInConfig(); err != nil {
		log.Fatalln("Failed to read config file")
	}
	// use the unmarshal way
	viper.Unmarshal(&cfg)
}
```
