Library providing routines to merge and validate JSON, YAML and/or TOML files

gophers

CONFLATE

Library providing routines to merge and validate JSON, YAML, TOML files and/or structs (godoc)

Typical use case: Make your application configuration files multi-format, modular, templated, sparse, location-independent and validated

Build Status Coverage Status Go Report Card

Description

Conflate is a library and cli-tool, that provides the following features :

  • merge data from multiple formats (JSON/YAML/TOML/go structs) and multiple locations (filesystem paths and urls)
  • validate the merged data against a JSON schema
  • apply any default values defined in a JSON schema to the merged data
  • expand environment variables inside the data
  • marshal merged data to multiple formats (JSON/YAML/TOML/go structs)

It supports draft-04, draft-06 and draft-07 of JSON Schema. If the key $schema is missing, or the draft version is not explicitly set, a hybrid mode is used which merges together functionality of all drafts into one mode. Improvements, ideas and bug fixes are welcomed.

Getting started

Run the following command, which will build and install the latest binary in $GOPATH/bin

go get github.com/miracl/conflate/...

Alternatively, you can install one of the pre-built release binaries from https://github.com/miracl/conflate/releases

Usage of Library

Please refer to the godoc and the example code

Usage of CLI Tool

Help can be obtained in the usual way :

$conflate --help
Usage of conflate:
  -data value
    	The path/url of JSON/YAML/TOML data, or 'stdin' to read from standard input
  -defaults
    	Apply defaults from schema to data
  -expand
    	Expand environment variables in files
  -format string
    	Output format of the data JSON/YAML/TOML
  -includes string
    	Name of includes array. Blank string suppresses expansion of includes arrays (default "includes")
  -noincludes
    	Switches off conflation of includes. Overrides any --includes setting.
  -schema string
    	The path/url of a JSON v4 schema file
  -validate
    	Validate the data against the schema
  -version
    	Display the version number

To conflate the following file ... :

$cat ./testdata/valid_parent.json
{
  "includes": [
    "valid_child.json",
    "valid_sibling.json"
  ],
  "parent_only" : "parent",
  "parent_child" : "parent",
  "parent_sibling" : "parent",
  "all": "parent"
}

...run the following command, which will merge valid_parent.json, valid_child.json, valid_sibling.json :

$conflate -data ./testdata/valid_parent.json -format JSON
{
  "all": "parent",
  "child_only": "child",
  "parent_child": "parent",
  "parent_only": "parent",
  "parent_sibling": "parent",
  "sibling_child": "sibling",
  "sibling_only": "sibling"
}

Note how the includes are loaded remotely as relative paths.

Also, note values in a file override values in any included files, and that an included file overrides values in any included file above it in the includes list.

If you instead host a file somewhere else, then just use a URL :

$conflate -data https://raw.githubusercontent.com/miracl/conflate/master/testdata/valid_parent.json -format JSON
{
  "all": "parent",
  "child_only": "child",
  "parent_child": "parent",
  "parent_only": "parent",
  "parent_sibling": "parent",
  "sibling_child": "sibling",
  "sibling_only": "sibling"
}

The includes here are also loaded as relative urls and follow exactly the same merging rules.

To output in a different format use the -format option, e.g. TOML :

$conflate -data ./testdata/valid_parent.json -format TOML
all = "parent"
child_only = "child"
parent_child = "parent"
parent_only = "parent"
parent_sibling = "parent"
sibling_child = "sibling"
sibling_only = "sibling"

To additionally use defaults from a JSON schema and validate the conflated data against the schema, use -defaults and -validate respectively :

$cat ./testdata/blank.yaml

$conflate -data ./testdata/blank.yaml -schema ./testdata/test.schema.json -validate -format YAML
Schema validation failed : The document is not valid against the schema : Invalid type. Expected: object, given: null (#)

$conflate -data ./testdata/blank.yaml -schema ./testdata/test.schema.json -defaults -validate -format YAML
all: parent
child_only: child
parent_child: parent
parent_only: parent
parent_sibling: parent
sibling_child: sibling
sibling_only: sibling

Note any defaults are applied before validation is performed, as you would expect.

If you don't want to intrusively embed an "includes" array inside your JSON, you can instead provide multiple data files which are processed from left-to-right :

$conflate -data ./testdata/valid_child.json -data ./testdata/valid_sibling.json -format JSON
{
  "all": "sibling",
  "child_only": "child",
  "parent_child": "child",
  "parent_sibling": "sibling",
  "sibling_child": "sibling",
  "sibling_only": "sibling"
}

Or alternatively, you can create a top-level JSON file containing only the includes array. For fun, lets choose to use YAML for the top-level file, and output TOML :

$cat toplevel.yaml
includes:
  - testdata/valid_child.json
  - testdata/valid_sibling.json

$conflate -data toplevel.yaml -format TOML
all = "sibling"
child_only = "child"
parent_child = "child"
parent_sibling = "sibling"
sibling_child = "sibling"
sibling_only = "sibling"

If you want to read a file from stdin you can do the following. Here we pipe in some TOML to override a value to demonstrate :

$echo 'all="MY OVERRIDDEN VALUE"' |  conflate -data ./testdata/valid_parent.json -data stdin  -format JSON
{
  "all": "MY OVERRIDDEN VALUE",
  "child_only": "child",
  "parent_child": "parent",
  "parent_only": "parent",
  "parent_sibling": "parent",
  "sibling_child": "sibling",
  "sibling_only": "sibling"
}

Note that in all cases -data sources are processed from left-to-right, with values in right files overriding values in left files, so the following doesn't work :

$echo 'all="MY OVERRIDDEN VALUE"' |  conflate -data stdin -data ./testdata/valid_parent.json  -format JSON
{
  "all": "parent",
  "child_only": "child",
  "parent_child": "parent",
  "parent_only": "parent",
  "parent_sibling": "parent",
  "sibling_child": "sibling",
  "sibling_only": "sibling"
}

You can optionally expand environment variables in the files like this :

$export echo MYVALUE="some value"
$export echo MYJSONMAP='{ "item1" : "value1" }'
$echo '{ "my_value": "$MYVALUE", "my_map": $MYJSONMAP }' | conflate -data stdin -expand -format JSON
{
  "my_map": {
    "item1": "value1"
  },
  "my_value": "some value"
}

Acknowledgements

Images derived from originals by Renee French https://golang.org/doc/gopher/

Similar Resources

TOML parser for Golang with reflection.

THIS PROJECT IS UNMAINTAINED The last commit to this repo before writing this message occurred over two years ago. While it was never my intention to

Jan 6, 2023

🛠 A configuration library for Go that parses environment variables, JSON files, and reloads automatically on SIGHUP

🛠 A configuration library for Go that parses environment variables, JSON files, and reloads automatically on SIGHUP

config A small configuration library for Go that parses environment variables, JSON files, and reloads automatically on SIGHUP. Example func main() {

Dec 11, 2022

A better way to marshal and unmarshal YAML in Golang

YAML marshaling and unmarshaling support for Go Introduction A wrapper around go-yaml designed to enable a better way of handling YAML when marshaling

Jan 4, 2023

YAML support for the Go language.

YAML support for the Go language Introduction The yaml package enables Go programs to comfortably encode and decode YAML values. It was developed with

Jan 8, 2023

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

It syncronizes the configuration described in a YAML file against your GitHub Organization

It syncronizes the configuration described in a YAML file against your GitHub Organization. Combined with a CI system, it can be used to implement GitOps for GitHub.

Jul 19, 2021

YAML support for the Go language

YAML support for the Go language

YAML support for the Go language

Dec 31, 2022

Golang config.yaml loader

Description goconfig is a configuration library designed using the following pri

May 31, 2022

SmartYAML - Go package to handle YAML

SmartYAML - Go package to handle YAML The smartyaml is a go package to handle parsed YAML files more confortable. This package is not a parser, it use

Feb 25, 2022
Comments
  • handling list as entity

    handling list as entity

    First off, thanks for this package! In my use case, it works almost too well. Say i have two sources, each with a list property: source.A:

    group_members:
      - alice
    

    source.B:

    group_members:
      - bob
    

    what i end up with by default is a list ["alice", "bob"]. I'm wondering if there is any way to treat lists as a whole, such that if i merge A then B, that source.B list is exclusive (ie just bob)?

  • panic: reflect: call of reflect.flag.mustBeExported on zero Value

    panic: reflect: call of reflect.flag.mustBeExported on zero Value

    Hi everyone,

    I'm in the progress of migrating a project from perl to go and have problems with a previously working JSON schema file with conflate. I first tried gojsonschema and the schema was valid there, but had no default value integration, so I turned to conflate.

    I ran into a panic (with my code and the conflate binary)

    $ ~/go/bin/conflate -data testdata/data.yaml -schema schema/data.schema.json -validate -defaults
    panic: reflect: call of reflect.flag.mustBeExported on zero Value
    
    goroutine 1 [running]:
    reflect.flag.mustBeExportedSlow(0x0)
            /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:222 +0xad
    reflect.flag.mustBeExported(...)
            /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:216
    reflect.Value.Set(0x147fbe0, 0xc000267c50, 0x194, 0x0, 0x0, 0x0)
            /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:1532 +0x56
    github.com/miracl/conflate.applyDefaultsRecursive(0xc00026a850, 0xb, 0x14816e0, 0xc0001dab10, 0x1453340, 0xc000267c50, 0x14816e0, 0xc0001dade0, 0x0, 0x0)
            /Users/andreas/go/pkg/mod/github.com/miracl/[email protected]/schema.go:208 +0xa1f
    github.com/miracl/conflate.applyObjectDefaults(0xc00026a780, 0x6, 0x14816e0, 0xc0001dab10, 0x14816e0, 0xc0001da0f0, 0xc0001dad80, 0x0, 0x0)
            /Users/andreas/go/pkg/mod/github.com/miracl/[email protected]/schema.go:247 +0x294
    github.com/miracl/conflate.applyDefaultsRecursive(0xc00026a780, 0x6, 0x14816e0, 0xc0001dab10, 0x1453340, 0xc0002678e0, 0x14816e0, 0xc0001dad80, 0x0, 0x0)
            /Users/andreas/go/pkg/mod/github.com/miracl/[email protected]/schema.go:215 +0x959
    github.com/miracl/conflate.applyObjectDefaults(0x150ad41, 0x1, 0x14816e0, 0xc0001dab10, 0x14816e0, 0xc0001da060, 0xc0001dab10, 0x10bd, 0x12bd)
            /Users/andreas/go/pkg/mod/github.com/miracl/[email protected]/schema.go:247 +0x294
    github.com/miracl/conflate.applyDefaultsRecursive(0x150ad41, 0x1, 0x14816e0, 0xc0001dab10, 0x1453340, 0xc0000ba980, 0x14816e0, 0xc0001dab10, 0xc000188417, 0x0)
            /Users/andreas/go/pkg/mod/github.com/miracl/[email protected]/schema.go:215 +0x959
    github.com/miracl/conflate.applyDefaults(0x1453340, 0xc0000ba980, 0x14816e0, 0xc0001dab10, 0x0, 0x0)
            /Users/andreas/go/pkg/mod/github.com/miracl/[email protected]/schema.go:160 +0x6c
    github.com/miracl/conflate.(*Schema).ApplyDefaults(0xc000267820, 0x1453340, 0xc0000ba980, 0x0, 0x0)
            /Users/andreas/go/pkg/mod/github.com/miracl/[email protected]/schema.go:77 +0x54
    github.com/miracl/conflate.(*Conflate).ApplyDefaults(...)
            /Users/andreas/go/pkg/mod/github.com/miracl/[email protected]/conflate.go:112
    main.main()
            /Users/andreas/go/pkg/mod/github.com/miracl/[email protected]/conflate/main.go:72 +0x7f2
    

    with this schema properties:

    ...
    "host" : {
              "type": [ "string", "null" ],
              "description": "Hostname",
              "pattern": "^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])$",
              "default": null
            },
    ...
    

    If I change it to use only string (and allow the empty string in the validation), it works:

    "host" : {
              "type": "string",
              "description": "Hostname",
              "pattern": "^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9]|)$",
              "default": ""
            },
    

    It's not a big limitation, but I need to change my previously working schema file in order to get it to work with conflate.

    Is this a bug worth noting?

    Best, Andreas

  • support supplementary oneOf, anyOf, allOf, noneOf section in schema with valid 'type'

    support supplementary oneOf, anyOf, allOf, noneOf section in schema with valid 'type'

    If you have a schem with a valid type and also oneOf anyOf, allOf or noneOf, then defaults are not applied.

    A typical use case is when you have an object schema that is required to have one field or another, but not both, (see https://stackoverflow.com/questions/24023536/json-schema-how-do-i-require-one-field-or-another-or-one-of-two-others-but-no). You can do this kind of thing with the following type of schema schema :

    {
        "title": "test",
        "type": "object",
        "properties": {
          "obj1": {
            "type": "object",
            "properties": {
              "prop1": {
                "type": "string",
                "default": "val1"
              }
            }
          },
          "obj2": {
            "type": "object",
            "properties": {
              "prop2": {
                "type": "string",
                "default": "val2"
              }
            }
          }
        },
        "oneOf": [
          {
            "required": [
              "obj1"
            ]
          },
          {
            "required": [
              "obj2"
            ]
          }       
        ]
    }
    

    However, conflate does not apply the object property defaults in the case of json input data such as :

    {
      "obj1": {} 
    }
    

    Conflate should output :

    {
      "obj1": {
        "prop1": "val1"
      }
    }
    
  • support anyOf, allOf, oneOf, and not, in applyDefaults

    support anyOf, allOf, oneOf, and not, in applyDefaults

    This is subtle, e.g. with anyOf it is possible that the data matches several subschemas each with different default values. Do we apply (a) the first default, (b) the defaults in turn (ordering of map is not necessarily the same as the original schema data file), (c) the first default providing there are no other schemas providing defaults, (d) no defaults (unless there is a single matching subschema).

    Similar issue for allOf, do we apply the defaults of each subschema in turn, overriding where necessary?

    For oneOf, we must check that the data matches a unique subschema, if it matches more than one then we cannot reliably determine which default (from which subschema) to apply.

    not is easy, since the data must never match any of the subschemas we know never to apply any of these defaults.

    e.g. https://spacetelescope.github.io/understanding-json-schema/reference/combining.html

Tmpl - A tool to apply variables from cli, env, JSON/TOML/YAML files to templates

tmpl allows to apply variables from JSON/TOML/YAML files, environment variables or CLI arguments to template files using Golang text/template and functions from the Sprig project.

Nov 14, 2022
Light weight, extensible configuration management library for Go. Built in support for JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper.
Light weight, extensible configuration management library for Go. Built in support for JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper.

koanf (pronounced conf; a play on the Japanese Koan) is a library for reading configuration from different sources in different formats in Go applicat

Jan 8, 2023
Generic templating tool with support of JSON, YAML and TOML data

gotempl Small binary used to generate files from Go Templates and data files. The following formats are supported: JSON YAML TOML Usage usage: gotempl

Jun 15, 2022
Golang Configuration tool that support YAML, JSON, TOML, Shell Environment

Configor Golang Configuration tool that support YAML, JSON, TOML, Shell Environment (Supports Go 1.10+) Usage package main import ( "fmt" "github.c

Dec 29, 2022
Golang library for reading properties from configuration files in JSON and YAML format or from environment variables.

go-config Golang library for reading properties from configuration files in JSON and YAML format or from environment variables. Usage Create config in

Aug 22, 2022
Go-yaml - Yaml parsing Toolkit For Golang

go-yaml 介绍 gopkg.in/yaml.v3 已经是个非常好用的包,但是在实际开发中总有类型转换带来的麻烦,go-yaml只是在它的基础上,简单的一层

Jan 13, 2022
TOML parser and encoder library for Golang

TOML parser and encoder library for Golang TOML parser and encoder library for Golang. This library is compatible with TOML version v0.4.0. Installati

Oct 11, 2022
Go library for the TOML language

go-toml Go library for the TOML format. This library supports TOML version v1.0.0-rc.3 Features Go-toml provides the following features for using data

Dec 27, 2022
JSON or YAML configuration wrapper with convenient access methods.

Config Package config provides convenient access methods to configuration stored as JSON or YAML. This is a fork of the original version. This version

Dec 16, 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