A lightweight yet powerful config package for Go projects

GoDoc Build Status Go Report Card Coverage Status Awesome

Config

GoLobby Config is a lightweight yet powerful config package for Go projects. It takes advantage of env files and OS variables alongside config files to be your ultimate requirement.

Documentation

Required Go Version

It requires Go v1.11 or newer versions.

Installation

To install this package run the following command in the root of your project

go get github.com/golobby/config

A simple example

The following example demonstrates how to set and get a simple key/value.

c, err := config.New()
// Check error...

c.Set("name", "John Doe")

name, err := c.Get("name")

Feeders

Feeders provide content of the configuration. Currently, these feeders exist out of the box:

  • Map: Feeds a simple map[string]interface{}.
  • Json: Feeds a JSON file.
  • JsonDirectory: Feeds a directory of JSON files.
  • Yaml: Feeds a Yaml file.

Of course, you are free to implement your feeders by implementing the Feeder interface.

You can pass your desired feeder through Options to the New() function this way:

c, err := config.New(config.Options{
    Feeder: TheFeederGoesHere,
})

Feeding using Map feeder

You don't like config files!? It's OK you can pass a Map feeder to the Config initializer like this example:

c, err := config.New(config.Options{
    Feeder: feeder.Map{
        "name":     "Hey You",
        "band":     "Pink Floyd",
        "year":     1979,
        "duration": 4.6,
    },
})
if err != nil {
    panic(err)
}

name, err := c.Get("name")
// OR
name, err := c.GetString("name")

year, err := c.Get("year")
// OR
year, err := c.GetInt("year")

year, err := c.Get("duration")
// OR
duration, err := c.GetFloat("duration")

Feeding using Json feeder

Storing configuration data in a JSON file could be a brilliant idea. The example below shows how to use the Json feeder.

config.json:

{
  "name": "MyAppUsingGoLobbyConfig",
  "version": 3.14,
  "numbers": [
    1,
    2,
    3
  ],
  "users": [
    {
      "name": "Milad Rahimi",
      "year": 1993,
      "address": {
        "country": "Iran",
        "state": "Lorestan",
        "city": "Delfan"
      }
    },
    {
      "name": "Amirreza Askarpour",
      "year": 1998,
      "address": {
        "country": "Iran",
        "state": "Khouzestan",
        "city": "Ahvaz"
      }
    }
  ]
}

Go code:

c, err := config.New(config.Options{
    Feeder: feeder.Json{Path: "path/to/config.json"},
})

v, err := c.Get("version") // 3.14

v, err := c.Get("numbers.2") // 3

v, err := c.Get("users.0.address.city") // Delfan

Feeding using Yaml feeder

Yaml files are a trend these days, so why not store configurations in them ?

config.yaml:

name: MyAppUsingGoLobbyConfig
version: 3.14
numbers: 
  - 1
  - 2
  - 3
users:
  - name: Milad Rahimi
    year: 1993
    address: 
      country: Iran
      state: Lorestan
      city: Delfan
  - name: Amirreza Askarpour
    year: 1998
    address:
      country: Iran
      state: Khouzestan
      city: Ahvaz 

Go code:

c, err := config.New(config.Options{
    Feeder: feeder.Yaml{Path: "path/to/config.yaml"},
})

v, err := c.Get("version") // 3.14

v, err := c.Get("numbers.2") // 3

v, err := c.Get("users.0.address.city") // Delfan

Feeding using JsonDirectory

If you have many configuration data and it doesn't fit in a single JSON file. In this case, you can use multiple JSON files and feed them using JsonDirectory feeder like this example:

Sample project directory structure:

- main.go
- config
- - app.json
- - db.json

app.json:

{
  "name": "MyApp",
  "version": 3.14
}

db.json:

{
  "sqlite": { "path": "app.db" },
  "mysql": { "host": "localhost", "user": "root", "pass": "secret" }
}

Go code:

c, err := config.New(config.Options{
    Feeder: feeder.JsonDirectory{Path: "config"},
})

v, err := c.Get("app.version") // 3.14
v, err := c.Get("db.mysql.host") // localhost

Feeding using YamlDirectory

If you have many configuration data and it doesn't fit in a single YAML file. In this case, you can use multiple YAML files and feed them using YamlDirectory feeder like this example:

Sample project directory structure:

- main.go
- config
- - app.yaml
- - db.yaml

app.yaml:

name: MyApp
version: 3.14

db.yaml:

sqlite:
  path: app.db

mysql:
  host: localhost
  user: root
  pass: secret

Go code:

c, err := config.New(config.Options{
    Feeder: feeder.YamlDirectory{Path: "config"},
})

v, err := c.Get("app.version") // 3.14
v, err := c.Get("db.mysql.host") // localhost

OS variables and environment files

OS variables

Sometimes you need to use environment variables stored in OS alongside your configuration data. You can refer to OS variables using a simple syntax, ${ VARIABLE }, in the config values. This example demonstrates how to use OS variables.

db.json:

{"name": "MyApp", "port": "${ APP_PORT }"}

Go code:

c, err := config.New(config.Options{
    Feeder: feeder.Json{Path: "db.json"},
})

v, err := c.Get("name") // MyApp
v, err := c.Get("port") // equivalent to os.Getenv("APP_PORT")

If you need to have a default value in case of lacking OS variable you can use this syntax:

${ VARIABLE | DEFAULT }

Example of JSON file using OS variable:

{"name": "MyApp", "port": "${ APP_PORT | 3306 }"}

environment files

You maybe want to use ".env" files. Good news! It's so easy to work with environment files. You can pass an environment file path alongside your config feeder when you initialize a new instance of Config.

Sample project directory structure:

- main.go
- .env
- config.json

config.json:

{"name": "MyApp", "key": "${ APP_KEY }", "port": "${ APP_PORT | 3306 }"}

.env:

APP_KEY=secret
APP_PORT=

Go code:

c, err := config.New(config.Options{
    Feeder: feeder.Json{Path: "config.json"},
    Env: ".env",
})

v, err := c.Get("name") // MyApp (from config.json)
v, err := c.Get("key") // secret (from .env)
v, err := c.Get("port") // 3306 (from config.json, the default value)

Reload the config and env files

One of the benefits of using config management tools is the ability to change the configurations without redeployment. The Config package takes advantage of OS signals to handle this need. It listens to the "SIGHUP" signal and reloads the env and config files on receive.

You can send this signal to your application with following shell command:

KILL -SIGHUP [YOUR-APP-PROCESS-ID]

To get your application process id you can use ps shell command.

Altogether!

In this section, we illustrate a complete example that shows many of the package features.

Sample project directory structure:

- main.go
- .env
- config
- - app.json
- - db.json

app.json:

{
  "name": "MyApp",
  "key": "${ APP_KEY }"
}

db.json:

{
  "sqlite": {
    "path": "app.db"
  },
  "mysql": { 
    "host": "${ DB_HOST | localhost }",
    "user": "${ DB_USER | root }",
    "pass": "${ DB_PASS | secret }"
  }
}

.env:

APP_KEY=theKey
DB_HOST=127.0.0.1
DB_USER=
DB_PASS=something

Go code:

_ := os.Setenv("DB_HOST", "192.168.0.13")

c, err := config.New(config.Options{
    Feeder: feeder.JsonDirectory{Path: "config"},
    Env: ".env",
})

v, err := c.Get("app.name") // MyApp (from app.json)
v, err := c.Get("app.key")  // theKey (from .env)
v, err := c.Get("db.mysql.host")  // 192.168.0.13 (from OS variables)
v, err := c.Get("db.mysql.user")  // root (from app.json, the default value)
v, err := c.Get("db.mysql.pass")  // something (from .env)

You may ask what would happen if the value existed in the config file, the environment file, and the OS variables? It's the order of the Config priorities:

  1. OS Variables
  2. Environment (.env) files
  3. Default Value

So if the value was defined is OS variables, the Config would return it. If it wasn't in OS variables, the Config would return the value stored in the environment file. If it also wasn't in the environment file, it'd eventually return the value stored in the config file as default value.

License

GoLobby Config is released under the MIT License.

Owner
GoLobby
GoLobby publishes open source packages with simplicity and fluent APIs in mind for GoLang
GoLobby
Comments
  • Cannot use feeder.Yaml literal

    Cannot use feeder.Yaml literal

    Hi!

    Sorry, i got this when used feeder.Yam{} on Go v1.15.6 at Linux os.

    cannot use feeder.Yaml literal (type feeder.Yaml) as type config.Feeder in field value:
        feeder.Yaml does not implement config.Feeder (Feed method has pointer receiver)
    

    the result based on example code that i'm try to my self

    c, err := config.New(config.Options{
        Feeder: feeder.Yaml{
            Path: "config/env.yaml",
        },
    })
    if err != nil {
        fmt.Println(err)
    }
    
    getConfigName, _ := c.Get("name")
    fmt.Println(getConfigName)
    

    Can i fix it, if there' mistake on my code? Or something happened in this package?

    Thank you.

  • OS variables not working on configuration data

    OS variables not working on configuration data

    this is an awesome go package. But I have trouble when using the OS variable on my configuration data. I am using go 1.14.

    I have db.json with some data below: {"name": "MyApp", "port": "${ APP_PORT }"}

    From my go code v, err := c.Get("port") // just return ${ APP_PORT } for the v

    so I get v with value ${ APP_PORT }, not the exact value of OS.Getenv("APP_PORT").

    fmt.Println(v) // ${ APP_PORT }

  • Fixed Issue8 - GetInt() would fail trying to get an int from json

    Fixed Issue8 - GetInt() would fail trying to get an int from json

    Fixes https://github.com/golobby/config/issues/8

    GetInt() would fail trying to get an int from json because all numbers in json become float64

    From the docs: https://golang.org/pkg/encoding/json/#Unmarshal

    To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:

    bool, for JSON booleans
    float64, for JSON numbers
    string, for JSON strings
    []interface{}, for JSON arrays
    map[string]interface{}, for JSON objects
    nil for JSON null
    
  • GetInt error

    GetInt error

    cat config.json { "host": "10.240.212.100", "username": "root", "password": "Password123", "user": ["user1", "user2"], "num": 90 }

    c, _ := config.New(config.Options{Feeder: feeder.Json{Path: "config.json"}}) host, err := c.GetInt("num") fmt.Println(err) fmt.Println(host) output: value for num is not int 0

  • Can not read env from a file name other than `.env`

    Can not read env from a file name other than `.env`

    Hi

    thanks for the great lib, works great

    so far has one problem.

    version: github.com/golobby/config/v3 v3.4.1

    import (
    	"log"
    	"os"
    
    	"github.com/golobby/config/v3"
    	"github.com/golobby/config/v3/pkg/feeder"
    )
    
    	if os.Getenv("NODE_ENV") == "local" {
    		c.AddFeeder(feeder.DotEnv{Path: ".env"})
    	} else if os.Getenv("NODE_ENV") == "test" {
    		c.AddFeeder(feeder.DotEnv{Path: ".envt"})
    	} else {
    		c.AddFeeder(feeder.Env{})
    	}
    

    The code above works for the NODE_ENV=="local" it stops working when NODE_ENV=="test"

    I get the following error

    2022/07/19 22:46:52 config: feeder error: config: cannot open env file; err: open .envt: no such file or directory

    I tried to change the file name to .env.test, .envTest, .env-test, no luck.

    What am I missing here? Thanks :)

  • Example Code in README.md has typo

    Example Code in README.md has typo

    Hello,

    Apologies, I know its petty that's why I didn't create a full PR.

    Shouldn't

    c := config.New()

    in the example code be

    c, err := config.New()

    Regards

  • Add license scan report and status

    Add license scan report and status

    Your FOSSA integration was successful! Attached in this PR is a badge and license report to track scan status in your README.

    Below are docs for integrating FOSSA license checks into your CI:

  • Suggest to upgrade to next version v1.2.x

    Suggest to upgrade to next version v1.2.x

    About the pull request, I've completed the following major works:

    1. Refactor the original config.go to three parts: base.go, config.go, and env.go, to achieve single-responsibility principle for each part.

    2. As the lookup() method is the key method to retrieve value by key, I update it for a bit performance consideration.

    3. Refactor the original config.New() method to pure New() method and the NewWithListener() method.

    4. (IMPORTANT) Add assign functions (and methods) to retrieve whole struct fields' value and/or whole slice elements' value

    5. All of the changes have passed the old tests.

    6. The added assigned utilities have passed the additional tests.

  • Consider moving feeders to separate packages

    Consider moving feeders to separate packages

    Having each feeder it their own package means that using one feeder does not add all the other dependencies to a project.

    Currently, using any feeder will cause the env, dotenv, yaml, and toml modules to be included as dependencies.
    As the number of feeders increases this will also add more and more dependencies.

    If they are in separate packages, while all the dependencies will show up in this module's go.mod, a dependent package will only get the dependencies for the feeder they use.

⚙️ Dead Simple Config Management, load and persist config without having to think about where and how.

Configo Dead Simple Config Management, load and persist config without having to think about where and how. Install go get github.com/UltiRequiem/conf

Apr 6, 2022
Go-config - Config parser for go that supports environment vars and multiple yaml files

go-multiconfig This package is able to parse yaml config files. It supports gett

Jun 23, 2022
A simple multi-layered config loader for Go. Made for smaller projects. No external dependencies.

config ⚠️ Work in progress! A simple multi-layered config loader for Go. Made for smaller projects. No external dependencies. Installation go get -u g

Dec 26, 2021
A lightweight config center written by golang.

A lightweight config center written by golang.

Jan 21, 2022
Simple, useful and opinionated config loader.

aconfig Simple, useful and opinionated config loader. Rationale There are many solutions regarding configuration loading in Go. I was looking for a si

Dec 26, 2022
go implementation of lightbend's HOCON configuration library https://github.com/lightbend/config

HOCON (Human-Optimized Config Object Notation) Configuration library for working with the Lightbend's HOCON format. HOCON is a human-friendly JSON sup

Dec 3, 2022
Composable, observable and performant config handling for Go for the distributed processing era

Konfig Composable, observable and performant config handling for Go. Written for larger distributed systems where you may have plenty of configuration

Dec 11, 2022
🔥🔥 🌈 Golang configuration,use to Viper reading from remote Nacos config systems. Viper remote for Naocs.

Viper remote for Nacos Golang configuration,use to Viper reading from remote Nacos config systems. Viper remote for Naocs. runtime_viper := viper.New(

Dec 6, 2022
create a bootable disk image from Docker image or a yaml config

docker2boot docker2boot creates a bootable disk from either a Docker image or a config yaml file Features status dns Y cloud-init Y network Y ssh TODO

Oct 30, 2022
Nacos is a service config & discovery.

Kratos Nacos example sc := []constant.ServerConfig{ *constant.NewServerConfig("127.0.0.1", 8848), } cc := &constant.ClientConfig{ NamespaceId:

Oct 28, 2021
Sidecar to watch a config folder and reload a process when it changes

A small (3MB uncompressed docker image), efficient (via inotify) sidecar to trigger application reloads when configuration changes.

Dec 29, 2022
Little Go tool to infer an uncrustify config file from an expected format

uncrustify-infer Little Go tool to infer an uncrustify config file from an expected format Install This tool relies on an uncrustify executable, you m

Oct 8, 2021
Ewwwwwww - Yuck Config
Ewwwwwww - Yuck Config

Eww Config What is it Using Eww Widgets to create a replacement for my bumblebee-status bars in i3 Window Manager. Eww allows you to create widgets an

Dec 29, 2022
Project my config into your prebuild

Projector A simple key value store per path. Building From Source git clone [email protected]:ThePrimeagen/projector.git cd projector # Install it where

Jun 23, 2022
Simple Config Format for Golang.

IndentText Simple Configuration Format that tries to be easy to use and understand at a glance. Unlike other formats, IndentText does not have any typ

Nov 26, 2021
Viper wrapper with config inheritance and key generation

piper - Simple Wrapper For Viper Single Source of Truth Generated Key Structs, No Typo Config Inheritance Multiple Config Strategies Support Cache For

Sep 26, 2022
A viewer for creating a one-page app that renders the config file as a webpage.

Matterbridge Config Viewer A viewer for creating a one-page app that renders the config file as a webpage. Local Development npm install npm run-scrip

Jul 9, 2021
App that generates a Matterbridge config file based on channel names.

Matterbridge Auto-Config App that generates a Matterbridge config file based on channel names. This remote configuration file* is generated based on s

Oct 15, 2022