Go (Con)Figure

Another post about Lightweight Config, a library I’ve recently built from the ground up, after creating various versions of it in previous projects.

Where previously, I’d tried to be clever and prepare the library for lots of possibilities, I took the opposite approach this time. I created a simple monolithic library to solve the core problem, and then in a later version added some new ideas that the simple idea opened up for me.

The Basic Challenge

In a service that has no specific injection framework, like Spring or DropWizard, and especially in a test, what’s the nicest way to load some configuration into an object.

E.g.

username: user
password: foo
urls:
  - http://foo.com
  - http://bar.com

We’d like to load this into an object:

public class Config {
    private String user;
    private String password;
    private List<String> urls;

    // getters and setters
}

This is easily achieved in one line with ConfigLoader.loadYmlConfigFromResource("config.yml", Config.class)

This assumes config.yml is in the appropriate resources.

Placeholders

What if we wanted to interpolate runtime values from environment variables or system properties? Well, that’s really the point of this framework. It’s intended to externalise the setting of values:

username: ${USERNAME}
password: ${PASSWORD}
urls:
  - http://foo.com
  - http://bar.com

Imports

If we have some common snippets of configuration to share between various configuration objects, then an import syntax would be nice. Even better if we can drive the import by a placeholder:

# config.yml
#import ${PROFILE}-config.yml

And then:

# dev-config.yml
username: username
password: foo
urls:
   - http://www.dev.com

And so on. Now we can load the config.yml but set PROFILE to determine which child config is also loaded. We can even put some common properties in the parent and it’ll all mash together into the load operation.

Plugins

What if we’re using a password/secret manager to load certain values dynamically? Let’s say we want to express that a certain value may be loaded from a secret:

username: !secret ${SECRET_ID}.user
password: !secret ${SECRET_ID}.password

We can add our custom tag – secret – to the loader:

Config myConfig = new ConfigLoader()
    .withTag("secret", secretPath -> secretsManager.load(secretPath))
    .loadAs("config.yml", Config.class);

Conclusion

With a little hindsight and a little code, I’ve put together a version of this framework I’m pleased to share with the open source community.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s