envconfig
An environment variable configuration mapper for Crystal. Uses syntax similar to JSON, YAML, and DB shards to map environment variables to a Crystal class. It's small.
Includes configuration printer for application startup as well.
What Problem Does This Solve?
Containerized application or other 12-factor apps often rely on environment
variables to configure themselves. Repeatedly writing code to read variables
from ENV[]
and then manually do type conversion, nil checking, etc is just
annoying. Other languages have packages for making this easy. Here's one for
Crystal.
Installation
-
Add the dependency to your
shard.yml
:dependencies: envconfig: github: relistan/envconfig.cr
-
Run
shards install
Usage
require "envconfig"
class TestConfig
EnvConfig.mapping({
prefix: {type: String, default: "l/", nilable: false, help: "URL prefix for redirects"},
redis_host: {type: String, default: "localhost", nilable: false, help: "Redis hostname to connect to"},
redis_port: {type: Int32, default: "6379", nilable: false, help: "Redis port to connect to"},
redis_pool: {type: Int32, default: "200", nilable: false, help: "Redis connection pool size"},
listen_port: {type: Int32, default: "8087", nilable: false, help: "Port to listen on"},
default_url: {type: String, nilable: false, help: "The default redirect URL"},
ssl_urls: {type: Bool, default: "false", nilable: false, help: "Generate HTTPS URLs?"},
unset_thing: {type: Int64, nilable: true}
}, "TEST"
)
end
config = TestConfig.new
puts config.redis_host
# OR dump all the values to a pretty-printed output
config.print_config()
The mapping()
macro supports all the fields above, with the same meaning as
the JSON
module in the stdlib.
The final argument to mapping()
is a prefix to place in front of all your
environment variables to prevent namespace collisions.
Printing Help Output
You may call the generated class method help()
method to generate Usage
information, including the available settings and types, and their default
values. It looks like this:
Usage:
The following vars apply. Types and defaults shown:
TEST_PREFIX (String) - URL Prefix for redirects [l/]
TEST_REDIS_HOST (String) - Redis hostname [localhost]
TEST_REDIS_PORT (Int32) - Redis port [6379]
TEST_REDIS_POOL (Int32) - Redis pool size [200]
TEST_LISTEN_PORT (Int32) - Port to listen on [8087]
TEST_DEFAULT_URL (String) - Default URL to send redirects to [*REQUIRED*]
TEST_SSL_URLS (Bool) - Generate HTTPS URLs? [false]
TEST_UNSET_THING (Int64) - [*NIL*]
You call it e.g. TestConfig.help()
as a class method, not an instance
method. This prevents having to initialize all the fields before printing.
Fields that are nilable
and have no default
show *NIL*
, while those
without defaults that are not nilable
show *REQUIRED*
.
The displayed text comes from the help
field in the mapping definition.
Printing Current Settings
Output from the pretty-printer print_config()
looks like this:
Settings ---------------------------------------------
* prefix: "l/"
* redis_host: "localhost"
* redis_port: 6379
* redis_pool: 200
* listen_port: 8087
* default_url: "http://example.com/"
* ssl_urls: false
-------------------------------------------------------
This is useful when debugging what was actually set.
You may optionally pass a block to print_config
that will be used to
obfuscate config values that should not be displayed. This is a block that will
be passed the key and value for each and is expected to return a string.
Something like:
config.print_config do |key, val|
if key =~ /redis/
"xxxx"
else
val.inspect
end
end
Contributing
- Fork it (https://github.com/your-github-user/envconfig/fork)
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request
Contributors
- Karl Matthias - creator and maintainer