confuse

package module
v1.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 29, 2024 License: MIT Imports: 14 Imported by: 0

README

Confuse

Confuse is a configuration library for Golang that is built on the idea of using a struct to manage your configuration data. This struct can then be populated with a fusion of configuration from any number of configuration sources such as environment variables, configuration files, and more.

The name Confuse was a merging between config and fusion, to indicate that two or more configuration files can be "fused" together in an override specification.

It is designed to be a lightweight, strongly typed and easy to use alternative to using map[string]interface{} to load configuration data, or accessing fields using .Get() from viper and parsing the types directly.

Features

  • Load configuration from yaml, json, toml and env files.
  • Load override configuration from environment variables.
  • Load configuration from multiple sources, that will override each other in order of precedence.
  • Load configuration into a struct, with specific data types for each field.
  • Allow usage for go-validator to validate configuration data (validate:"required").
  • Generate a json-schema from your configuration struct to use with .json and .yaml files.

Installation

go get github.com/ls6-events/confuse

Usage

Basic
package main

import (
	"fmt"
	"github.com/davecgh/go-spew/spew"
	"github.com/ls6-events/confuse"
)

type Config struct {
	// `config` tag is not required, we will check for the field name in it's case, snake_case, kebab-case, camelCase and PascalCase forms.
	Name string `config:"name"`
	Port int    `config:"port"`

	// You can also use the `validate` tag to validate the configuration data.
	Host string `config:"host" validate:"required"`

	// You can also use nested structs.
	Database struct {
		Host string `config:"host"`
		Port int    `config:"port"`
	} `config:"database"`
}

func main() {
	// Create a new configuration struct.
	var config Config

	// Load the configuration from the default sources.
	err := confuse.New(confuse.WithSourceFiles("./config.yaml")).Unmarshal(&config)

	// Check for errors.
	if err != nil {
		panic(err)
	}

	// Print the configuration. 
	fmt.Printf("Name: %s\n", config.Name)
	fmt.Printf("Port: %d\n", config.Port)
	fmt.Printf("Host: %s\n", config.Host)

	// Print the nested configuration.
	spew.Dump(config.Database)
}

Check out more from the examples directory for different use cases.

Multiple Sources

There is an example of using multiple sources in the examples directory, but here is a quick example.

package main

import (
    "fmt"
    "github.com/ls6-events/confuse"
)

type Config struct {
    Name string `config:"name"`
    Port int    `config:"port"`
}

func main() {
    // Create a new configuration struct.
    var config Config

    // Load the configuration from the default sources.
    err := confuse.New(
        confuse.WithSourceFiles("./config.yaml", "./override.json"),
    ).Unmarshal(&config)

    // Check for errors.
    if err != nil {
        panic(err)
    }

    // Print the configuration. 
    fmt.Printf("Name: %s\n", config.Name) // override
    fmt.Printf("Port: %d\n", config.Port) // 8080
}
# config.yaml
name: "config"
port: 8080
// override.json
{
  // This will override the name from the config.yaml file.
    "name": "override"
}

You can have as many sources as you want, and they will be loaded in order of precedence. The last source will override the previous sources.

Environment Variables

You can also load configuration from environment variables. This is done by using the confuse.WithSourceEnv() option.

package main

import (
    "fmt"
    "github.com/ls6-events/confuse"
)

type Config struct {
    Name string `config:"name"`
    Port int    `config:"port"`
}

func main() {
    // Create a new configuration struct.
    var config Config

    // Load the configuration from the default sources.
    err := confuse.New(
		confuse.WithSourceFiles("./config.yaml"), 
		confuse.WithEnvironmentVariables(true),
    ).Unmarshal(&config)

    // Check for errors.
    if err != nil {
        panic(err)
    }

    // Print the configuration. 
    fmt.Printf("Name: %s\n", config.Name) // override
    fmt.Printf("Port: %d\n", config.Port) // 8080
}

This will allow the env variable NAME to override the name field in the configuration struct. The env variable PORT will override the port field in the configuration struct. If there is a nested struct, the joining operator of __ will be used to join the field names together. If you want to change this, there is the option confuse.WithEnvironmentVariablesSeparator(separator string) function to change it.

Validation

You can also use the validate tag to validate the configuration data. This is done by using the confuse.WithValidation(true) option.

package main

import (
    "fmt"
    "github.com/ls6-events/confuse"
)

type Config struct {
    Name string `config:"name" validate:"required"`
    Port int    `config:"port" validate:"required"`
}

func main() {
    // Create a new configuration struct.
    var config Config

    // Load the configuration from the default sources.
    err := confuse.New(
        confuse.WithSourceFiles("./config.yaml"), 
        confuse.WithValidation(true),
    ).Unmarshal(&config)

    // Check for errors.
    if err != nil {
        panic(err)
    }

    // Print the configuration. 
    fmt.Printf("Name: %s\n", config.Name) // override
    fmt.Printf("Port: %d\n", config.Port) // 8080
}

There is an example of using validation in the examples directory. It will also use these tags to generate the correct JSON schema where appropriate.

JSON Schema

You can also generate a JSON schema from your configuration struct. This is done by using the confuse.WithExactOutputJSONSchema(filepath string) option.

package main

import (
    "fmt"
    "github.com/ls6-events/confuse"
)

type Config struct {
    Name string `config:"name" validate:"required"`
    Port int    `config:"port" validate:"required"`
}

func main() {
    // Create a new configuration struct.
    var config Config

    // Load the configuration from the default sources.
    err := confuse.New(
        confuse.WithSourceFiles("./config.yaml"), 
        confuse.WithExactOutputJSONSchema("./schema.json"),
    ).Unmarshal(&config)

    // Check for errors.
    if err != nil {
        panic(err)
    }

    // Print the configuration. 
    fmt.Printf("Name: %s\n", config.Name) // override
    fmt.Printf("Port: %d\n", config.Port) // 8080
}

There is an example of using validation in the examples directory. It will also use these tags to generate the correct JSON schema where appropriate.

Note, we also have an option to create a fuzzy schema, which will not include the required tags (it's useful for setting the schema of override files as the nature of them may indicate that not all properties are set). This is done by using the confuse.WithFuzzyOutputJSONSchema(filepath string) option.

Custom Sources

You can also create your own custom sources. This can be done by using the confuse.WithSourceLoaders(func() (map[string]any, error)) option.

Note: this step happens before the unmarshalling to a struct. Therefore if you want it to override any existing configuration keys, you must preserve the case of the keys.

package main

import (
    "fmt"
    "github.com/ls6-events/confuse"
)

type Config struct {
    Name string `config:"name"`
    Port int    `config:"port"`
}

func main() {
    // Create a new configuration struct.
    var config Config

    // Load the configuration from the default sources.
    err := confuse.New(
        confuse.WithSourceFiles("./config.yaml"), 
        confuse.WithSourceLoaders(func() (map[string]any, error) {
            return map[string]any{
                "name": "override",
            }, nil
        }),
    ).Unmarshal(&config)

    // Check for errors.
    if err != nil {
        panic(err)
    }

    // Print the configuration. 
    fmt.Printf("Name: %s\n", config.Name) // override
    fmt.Printf("Port: %d\n", config.Port) // 8080
}

There is an example of using custom sources in the examples directory.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type JSONSchema

type JSONSchema struct {
	SchemaUri   string `json:"$schema"`
	IDUri       string `json:"$id"`
	Title       string `json:"title"`
	Description string `json:"description"`
	validjsonator.Schema
}

type Loader added in v1.1.0

type Loader func() (map[string]any, error)

type Option

type Option func(*Service)

func WithCustomValidator

func WithCustomValidator(validator *validator.Validate) Option

WithCustomValidator sets the validator to use to validate the unmarshalled configuration. If this is not set, the default will be used will be used.

func WithEnvironmentVariables

func WithEnvironmentVariables(shouldUseEnvironmentVariables bool) Option

WithEnvironmentVariables sets the flag to indicate whether to use the environment variables to override the configuration. If this is set to true, the environment variables will be used to override the configuration.

func WithEnvironmentVariablesPrefix

func WithEnvironmentVariablesPrefix(prefix string) Option

WithEnvironmentVariablesPrefix sets the prefix of the environment variables to use to override the configuration. If this is set, only the environment variables with the prefix will be used to override the configuration.

func WithEnvironmentVariablesSeparator

func WithEnvironmentVariablesSeparator(separator string) Option

WithEnvironmentVariablesSeparator sets the separator of the environment variables to use to override the configuration. By default, the separator is "__".

func WithExactOutputJSONSchema

func WithExactOutputJSONSchema(path string) Option

WithExactOutputJSONSchema sets the path to the output JSON schema file that is generated from the unmarshalled configuration. If this is set, the output JSON schema will be written to this file.

func WithFuzzyOutputJSONSchema

func WithFuzzyOutputJSONSchema(path string) Option

WithFuzzyOutputJSONSchema sets the path to the output JSON schema file that is generated from the unmarshalled configuration. It is similar to ExactOutputJSONSchema, but all the required fields are made optional. This is useful when you want to use the override files mechanism to override only a subset of the configuration. If this is set, the output JSON schema will be written to this file.

func WithJSONSchemaKeyModifier

func WithJSONSchemaKeyModifier(modifier func(string) string) Option

WithJSONSchemaKeyModifier sets the function to use to modify the JSON schema key. If this is set, the function will be used to modify the JSON schema key. By default, it is set to strcase.ToSnake.

func WithMergoConfig

func WithMergoConfig(config ...func(*mergo.Config)) Option

WithMergoConfig sets the list of options to use when merging the configuration using dario.cat/mergo. By default it just uses mergo.WithOverride.

func WithSourceFiles

func WithSourceFiles(files ...string) Option

WithSourceFiles sets the source files to read from. It can be used multiple times to read from multiple files. The first file in the list takes the lowest precedence, and the last file takes the highest precedence. E.g. if the same key is defined in both files, the value in the last file will be used. Base -> Override 1 -> Override 2 -> Override 3

func WithSourceLoaders added in v1.1.0

func WithSourceLoaders(loader ...Loader) Option

WithSourceLoaders sets the source loaders to use to load the files. It can be used multiple times to load from multiple loaders. The first loader in the list takes the lowest precedence, and the last loader takes the highest precedence. They take a higher precedence than SourceFiles. E.g. if the same key is defined in both files, the value in the last loader will be used. Base -> Override 1 -> Override 2 -> Override 3

func WithValidation

func WithValidation(shouldValidate bool) Option

WithValidation sets the flag to indicate whether the unmarshalled configuration should be validated against the JSON schema. If this is set to true, the unmarshalled configuration will be validated against the JSON schema.

type Service

type Service struct {
	// SourceFiles is the list of files to load.
	// The first file in the list takes the lowest precedence, and the last file takes the highest precedence.
	// E.g. if the same key is defined in both files, the value in the last file will be used.
	// Base -> Override 1 -> Override 2 -> Override 3
	SourceFiles []string

	// SourceLoaders is the list of loaders to use to load the files.
	// The first loader in the list takes the lowest precedence, and the last loader takes the highest precedence.
	// They take a higher precedence than SourceFiles, but lower than EnvironmentVariables.
	// E.g. if the same key is defined in both files, the value in the last loader will be used.
	// Base -> Override 1 -> Override 2 -> Override 3
	SourceLoaders []Loader

	// ExactOutputJSONSchema is the path to the output JSON schema file that is generated from the unmarshalled configuration.
	// If this is set, the output JSON schema will be written to this file.
	ExactOutputJSONSchema string

	// FuzzyOutputJSONSchema is the path to the output JSON schema file that is generated from the unmarshalled configuration.
	// It is similar to ExactOutputJSONSchema, but all the required fields are made optional.
	// This is useful when you want to use the override files mechanism to override only a subset of the configuration.
	// If this is set, the output JSON schema will be written to this file.
	FuzzyOutputJSONSchema string

	// JSONSchemaKeyModifier is the function to use to modify the JSON schema key.
	// If this is set, the function will be used to modify the JSON schema key.
	// By default, it is set to strcase.ToSnake.
	JSONSchemaKeyModifier func(string) string

	// ShouldValidate is a flag to indicate whether the unmarshalled configuration should be validated against the JSON schema.
	// If this is set to true, the unmarshalled configuration will be validated against the JSON schema.
	ShouldValidate bool

	// Validator is the validator to use to validate the unmarshalled configuration.
	// If this is not set, nil will be used.
	Validator *validator.Validate

	// ShouldUseEnvironmentVariables is a flag to indicate whether to use the environment variables to override the configuration.
	// If this is set to true, the environment variables will be used to override the configuration.
	// It overrides the configuration from the files and the loaders.
	ShouldUseEnvironmentVariables bool

	// EnvironmentVariablesPrefix is the prefix of the environment variables to use to override the configuration.
	// If this is set, only the environment variables with the prefix will be used to override the configuration.
	EnvironmentVariablesPrefix string

	// EnvironmentVariablesSeparator is the separator of the environment variables to use to override the configuration.
	// By default, the separator is "__".
	EnvironmentVariablesSeparator string

	// MergoConfig is the list of options to use when merging the configuration using dario.cat/mergo.
	// By default it just uses mergo.WithOverride.
	MergoConfig []func(*mergo.Config)
}

Service is the configuration for confuse, which is used to unmarshal config files

func New

func New(opts ...Option) *Service

func (*Service) Unmarshal

func (s *Service) Unmarshal(obj any) error

Unmarshal unmarshals the configuration files into the given struct. It returns an error if the unmarshalling fails.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL