Even in simple, smaller applications we have to deal with configuration of some kind. Since we all know that hardcoding config values sucks, we tend to pick the easy-yet-flexible and powerful method - reading values from environmental variables. In this short post, I’ll show you how to embrace functional concepts and make configuration reading type safe. And, as a bonus, you’ll get fancy error reporting in case something goes left.
Our goal is to read all necessary values at app startup — we absolutely don’t want to find out that the database password is missing in the middle of http request processing — and terminate with a human-readable message in the console if something is missing or invalid.
We will use the excellent fp-ts & io-ts libraries from Giulio Canti. Some could argue that there are other fish in the sea, but if you aim for the best, search no more ;-)
Enough talk, let’s start with the code!
As you can see, decoding yields transform either the value or error if something fails.
Guilio provides us with a few built-in decoders and combinators, so we can create our reader by combining them (as any decent functional developer would do).
Primitive decoders don’t do anything fancy:
But as soon as we combine them, the magic starts to happen:
Let’s say, we need to read db user, password, and port that our application will be listening on. We use type combinator for composing the decoder:
Maybe we want some of the properties to be optional and to supply default values:
Now we can extract static type from the decoder instance:
And use it in our application like this:
Happy functional coding! λ