Skip to content

clarafu/envstruct

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

envstruct

Library to parse env into a struct

What is envstruct

It supports all basic parsing of environment variables into the struct object given. An example of it's usage is that you would pass in the following struct:

type MyStruct struct {
  Field string `tag:"field"`
}

envstruct will then fetch the environment variable FIELD, parse it and set it back into your struct. So if you had FIELD=foo set as an envionment variable, the result will be:

MyStruct{
  Field: "foo"
}

I started this project in order to satisfy my use case of being able to use a library that will parse environment variables into a struct using tag values, including the tag values of nested structs. There are a lot of libraries out there that can parse environment variables into structs, but the environment variable that it fetches was built up either using the field names or field tag values that don't include tag values on nested structs.

For example, it supports the following struct:

type MyStruct struct {
  Nested struct {
    Field string `tag:"field"`
  } `tag:"nested"`
}

Which the Field value will be fetched using NESTED_FIELD as the string to fetch the environment variable.

How to use it

You can use envstruct by first configuring a few settings.

Settings Desciptions
Prefix Optional and if set, is used as the prefix to any environment variable fetching. For example, if we are fetching env string FIELD1 and we have prefix set to BAR, then BAR_FIELD1 will be used to fetch the environment variable.
TagName Used for fetching the tag value from the field. A built up string using this tag value will be used to fetch the environment variable. Can be placed on a struct or field.
Delimiter Used as the separater for multiple values within a struct or map. It is defaulted to a comma ,. It is used so that in the environment variable, there can exist slices such as PREFIX_FIELD=foo,bar.
Unmarshaler Used to unmarshal the string into the field types. For example, you can pass in a yaml or json unmarshaler.
OverrideName Optional and if set, is used to fetch the tag value from the field that will be used to fetch the environment variable. It is used to override the string built using the TagName. The tag value from OverrideName will be used directly and will not be modified with upper casing, prefixing or attaching nested struct tag values.
IgnoreTagName Optional and if set, will be used to recognize when a tag should not be included in the built up string for fetching the environment value.
StripValue Optional and if set true, envstruct will remove all characters including and after the first comma in the tag value that matches the TagName. The purpose of this is to allow the reuse of tags with other libraries, for example, to reuse yaml tags that might have an ,omitempty value appended to the tag value like yaml:"value,omitempty".

Then you call FetchEnv off of envstruct.

env := envstruct.Envstruct{
  Prefix: "prefix",
  TagName: "tag",

  Parser: envstruct.Parser{
    Delimiter: ",",
    Unmarshaler: yaml.Unmarshal,
  },
}

type Example struct {
  Field string `tag:"field"`
}

mystruct := Example{}

err := env.FetchEnv(&mystruct)
if err != nil {
  return nil
}

From the example above, if the environment variable PREFIX_FIELD=foo was set while it was running then mystruct.Field will be populated with the string foo.

How are environment variables parsed

The types of variables that it parses depends on what kind of Unmarshaler is passed to the envstruct. The only special cased types are slices and maps, which are parsed by envstruct and then each item is passed to the Unmarshaler. Multiple items within one environment variables are separated by the Delimiter that is set on the envstruct.

An example of a slice would be:

PREFIX_SLICE=foo,bar

An example of a map would be:

PREFIX_MAP=foo:foo1,bar:bar1

Each part of the string that is used to build up the environment variable is uppercased and appended to each other using an underscore _.

How is the struct parsed

The exact string that is used to fetch the environment variable is built up using the tags within the struct fields. The TagName will be used to fetch the tag value from the struct fields for building up the environment variable string.

A simple example is a basic struct with a field:

type MyStruct struct {
  FieldName string `tag:"field"`
}

FIELD will be the string that is used to fetch the value of the environment variable for FieldName.

If the field does not have a tag that matches the TagName, it will not be fetched from an environment variable. envstruct will only fetch fields that has a tag that matches the TagName.

Fields within nested structs are supported, and the environment variable string is built up with the tag values from each nested struct that has a tag matching the TagName.

For example,

type MyStruct struct {
  Foo struct {
    Bar struct {
      FieldName string `tag:"field"`
    }
  } `tag:"foo"`
}

The example above would result in the string FOO_BAR to be used to fetch the environment variable for MyStruct.Foo.Bar.FieldName. If the Prefix was set to PREFIX, then PREFIX_FOO_BAR will be used to fetch the environment variable for MyStruct.Foo.Bar.FieldName.

Overriding the tag

The string that is built up using the TagName which is used to fetch the environment variable can be overriden using the OverrideName field. If you configure the OverrideName field, any field that contains a tag that matches the value set in OverrideName will use the value of that tag to fetch its environment variable. The override tag will only be recognized on fields on a struct and not nested structs.

The value of the tag matching the OverrideName will be used directly, that means it will not be uppercased, appended with nested struct tags or prefixed like how the regular built up string using the TagName is.

For example, in the example below we have set the OverrideName to be value override.

type MyStruct struct {
  Foo struct {
    Bar struct {
      FieldName string `tag:"field" override:"override_field"`
    }
  } `tag:"foo"`
}

Since FieldName has a tag override, the value of the override value will be used to fetch the environment variable. In the example, override_field will be used to fetch the environment variable, rather than FOO_BAR which would have been used if the field did not contain the override tag.

A field can have multiple override tag values that are comma separated. For example,

type MyStruct struct {
  FieldName string `tag:"field" override:"O_FIELD1,O_FIELD2"`
}

O_FIELD1 and O_FIELD2 will be used to try and fetch the environment variable for FieldName. It is ordered in terms of precedence from left to right, so if a value is fetched from O_FIELD1 then we will use that value and not try to fetch using O_FIELD2.

Ignoring certain tags

You can ignore certain tags so that they will not be included in the built up string for fetching the environment value using the IgnoreTagName configuration. The string that it is set to a true value will be used to find when a field should not be included.

Typically this will be used for nested struct tags, where you do not want to include the nested tag value in the environment variable lookup.

An example below with the IgnoreTagName set to ignore_env and TagName set to tag:

type MyStruct struct {
  Foo struct {
    Bar struct {
      FieldName string `tag:"field"`
    } `tag:"bar" ignore_env:"true"`
  } `tag:"foo"`
}

The example above would result in an environment variable fetch using FOO_FIELD where it does not include BAR within the built up string.

If the ignore_env was set to false, then the tag name will be included in the environment variable string.

Important things to note!

If there is a nested struct that is a pointer, envstruct will only traverse it if it is already initialized. For example, if you have MyStruct with a nested Foo struct that is of a pointer type

type MyStruct struct {
  Foo *struct {
    FieldName string `tag:"field"`
  } `tag:"foo"`
}

Foo will need to be initialized before it is passed into envstruct for it to be able to traverse through the fields within the nested pointer struct. This is because we don't want to initialize pointers within envstruct.

About

Library to parse env into struct

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages