ProductPromotion
Logo

Go.Lang

made by https://0x3d.site

GitHub - Yiling-J/piper: ๐Ÿ›  Viper wrapper with config inheritance and key generation
๐Ÿ›  Viper wrapper with config inheritance and key generation - Yiling-J/piper
Visit Site

GitHub - Yiling-J/piper: ๐Ÿ›  Viper wrapper with config inheritance and key generation

GitHub - Yiling-J/piper: ๐Ÿ›  Viper wrapper with config inheritance and key generation

piper - Simple Wrapper For Viper

example workflow Go Report Card

  • Single Source of Truth
  • Generated Key Structs, No Typo
  • Config Inheritance
  • Multiple Config Strategies Support
  • Cache For Better Performance

Why Piper

If you are familiar with Django, this is how Django settings module looks like:

โ””โ”€โ”€ settings
    โ”œโ”€โ”€ base.py
    โ”œโ”€โ”€ dev.py
    โ”œโ”€โ”€ stage.py
    โ””โ”€โ”€ prod.py

dev.py will inherit from base.py, also stage.py will inherit from dev.py.

Start Django with selected setting:

export DJANGO_SETTINGS_MODULE=mysite.settings.prod
django-admin runserver

And this is how you access settings in Django:

from django.conf import settings

author = settings.Author

I want to have similar experience with Viper, so here comes this wrapper:

โ””โ”€โ”€ config
    โ”œโ”€โ”€ base.toml
    โ”œโ”€โ”€ dev.toml
    โ”œโ”€โ”€ stage.toml
    โ””โ”€โ”€ prod.toml

This is how you access config using piper:

import "your_project/config"

func main() {
	piper.Load("config/stage.toml")
	author = piper.GetString(config.Author)
}

Check example folder for more details.

Installation

go get github.com/Yiling-J/piper/cmd

Add Config Files

Add your config files to your config folder, usually your config folder should be under project root folder.

toml example, you can also use yaml or json.

project
โ””โ”€โ”€ config
    โ”œโ”€โ”€ base.toml
    โ”œโ”€โ”€ dev.toml
    โ”œโ”€โ”€ stage.toml
    โ””โ”€โ”€ prod.toml

To support inheritance, you need to add a special key to your config file called pp_imports

pp_imports = ["base.toml", "dev.toml"]

Piper will resolve that automatically. Also order matters here, this line means import base.toml first, then import dev.toml and merge. After all pp_imports merged, import current file.

Config Key Generation

Run code generation from the root directory of the project as follows:

go run github.com/Yiling-J/piper/cmd your_config_folder

In this step piper will load all files in your config folder and merge them together. Then piper will generate config.go under your config folder, include all your config keys. Also you will see the config structure when piper generating code.

After code genertation, your config folder should look like:

โ””โ”€โ”€ config
    โ”œโ”€โ”€ base.toml
    โ”œโ”€โ”€ dev.toml
    โ”œโ”€โ”€ stage.toml
    โ”œโ”€โ”€ prod.toml
    โ””โ”€โ”€ config.go

Use Piper

Strategy I - Embed

embed your config folder into your code, single executable when you deploy.

import (
	"github.com/Yiling-J/piper"
	"your_project/example/config"
)

//go:embed config/*
var configFS embed.FS

piper.SetFS(configFS)
piper.Load("config/stage.toml")
author := piper.GetString(config.Author)

Strategy II - Embed with Env

embed your config folder into your code, single executable when you deploy, and replace secret with env.

import (
	"github.com/Yiling-J/piper"
	"your_project/example/config"
)

//go:embed config/*
var configFS embed.FS

os.Setenv("SECRET", "qux")
piper.SetFS(configFS)
// make sure turn on AutomaticEnv first then loading config,
// this way the env vaiable is also cached, so IGet* methods can work properly
piper.V().AutomaticEnv()
piper.Load("config/stage.toml")
secret := piper.GetString(config.Secret)

Strategy III - Copy config directory

copy config folder when building docker image, so the true config folder exists.

import (
	"github.com/Yiling-J/piper"
	"your_project/example/config"
)

piper.Load("config/stage.toml")
author := piper.GetString(config.Author)

Strategy IV - Mix embed and copy directory

Embed your config folder, but keep some secret keys in a real config file.

import (
	"github.com/Yiling-J/piper"
	"your_project/example/config"
)

//go:embed config/*
var configFS embed.FS

// "config/stage_with_secret.toml" is not in source code,
// may come from docker build or k8s ConfigMap
piper.SetFS(configFS)
piper.Load("config/stage_with_secret.toml")
author := piper.GetString(config.Author)

True directory will take precedence over embeded directory.

Access Viper

Piper is just a wrapper, so you can always get the wrapped viper instance:

v := piper.V()

Be careful when using viper directly to load config, piper may not work properly.

Piper or Pipers?

Piper comes ready to use out of the box. There is no configuration or initialization needed to begin using Piper. Since most applications will want to use a single central repository for their configuration, the piper package provides this. It is similar to a singleton.

In all of the examples above, they demonstrate using piper in its singleton style approach.

Working with multiple pipers

You can also create many different pipers for use in your application. Each will have its own unique set of configurations and values. Each can read from a different config file. All of the functions that piper package supports are mirrored as methods on a piper.

Example:

x := piper.New()
y := piper.New()

x.Load("config/x.toml")
y.Load("config/y.toml")

// access viper
// p := x.V

When working with multiple pipers, it is up to the user to keep track of the different pipers.

Performance

Sometimes you may find viper a little slow, because viper need to check in the following order on Get: flag, env, config file, key/value store. If you have confidence some of your configs won't change, you can use piper's IGet* methods. Piper will build a configs cache on Load, and those IGet* methods will get config from cache directly.

goos: darwin
goarch: amd64
pkg: github.com/Yiling-J/piper/integration
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz

BenchmarkGet-12           895533              1278 ns/op
BenchmarkIGet-12        19141876                61.35 ns/op

Articles
to learn more about the golang concepts.

Resources
which are currently available to browse on.

mail [email protected] to add your project or resources here ๐Ÿ”ฅ.

FAQ's
to know more about the topic.

mail [email protected] to add your project or resources here ๐Ÿ”ฅ.

Queries
or most google FAQ's about GoLang.

mail [email protected] to add more queries here ๐Ÿ”.

More Sites
to check out once you're finished browsing here.

0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory