Description
Flasked injects application environment configuration at runtime based on given ENV variables and a mapping.
This is pretty useful for applications following the 12 factor app principle stated by Heroku.
For the specific details see http://12factor.net/config.
Also in container environments like Docker this comes in quite handy when you're literally forced to use ENV vars for
configuration of your specific container at startup time.
Flasked alternatives and similar packages
Based on the "Configuration" category.
Alternatively, view Flasked alternatives based on common mentions on social networks and blogs.
-
conform
Easy, powerful, and extendable configuration tooling for releases. -
confex
Useful helper to read and use application configuration from environment variables. -
Skogsrå
Library to manage OS environment variables and application configuration options with ease -
weave
JIT configuration loader that works with Kubernetes and Docker Swarm. -
configparser_ex
A simple Elixir parser for the same kind of files that Python's configparser library handles -
hush_aws_secrets_manager
An AWS Secrets Manager Provider for Hush -
hush_gcp_secret_manager
A Google Secret Manager Provider for Hush -
mahaul
Supercharge your environment variables in Elixir. Parse and validate with compile time access guarantees, defaults, fallbacks and app pre-boot validations. -
figaro_elixir
Environmental variables manager based on Figaro for Elixir projects -
Enux
utility package for loading, validating and documenting your app's configuration variables from env, json, jsonc and toml files at runtime and injecting them into your environment -
CFEnv
Environmental helpers for cloudfoundry, parsing and returning values off VCAP_SERVICES and VCAP_APPLICATON
Elixir and Phoenix Application Security Platform
Do you think we are missing an alternative of Flasked or a related project?
Popular Comparisons
README
Flasked
flasked - something (an elixir) bottled into a flask
Flasked injects application environment configuration at runtime based on given ENV variables and a mapping.
This is pretty useful for applications following the 12 factor app principle stated by Heroku.
For the specific details see http://12factor.net/config.
Also in container environments like Docker this comes in quite handy when you're literally forced to use ENV vars for configuration of your specific container at startup time.
# provide ENV var
MY_FLASKED_APP_FOO=this_is_foo iex -S mix
# use the ENV var value in the app
iex(1)> Application.get_env(:my_flasked_app, :foo)
"this_is_foo"
Rationale
OTP apps/releases are normally preconfigured and do not provide the tooling for runtime configuration out of the box. At least it is quite difficult and involves a lot of customization of every app or release.
The Phoenix framework only provides to set the PORT
via ENV
variable, the rest still has to be hard-coded.
Fiddling with the release configuration to enable more variables to be set at runtime is quite cumbersome and not well documented.
On the other hand, especially with containerization in mind, most of the environment specific configuration should be done at runtime, meaning you should not hard-code any environment/stage/role based configuration.
I agree with separation of code and configuration, because configs are state, and the application artifacts should be stateless.
There are similar projects like Dotenv, Envy and ExConf, but they don't go far enough for what I wanted. Most of them tackle only a very low-level need or are useful in development only.
Why no YAML or JSON for the mapping?
I'll just quote José Valim here:
Please avoid YAML in Elixir projects. It is unnecessarily complex, both in implementation and usage. Elixir already provides config files.
And Code.eval_file("some/file.exs")
does the job just fine, really.
Installation
# mix.exs
def deps do
[{:flasked, "~> 0.4"}]
end
Usage
Add flasked to applications
Make sure Flasked is in the applications
list, preferably the very first one.
(If it is the first, you can even reconfigure the logger before startup.)
def application do
[
applications: [:flasked],
# ...
]
end
Standalone one-shot usage
# If you want to control it yourself or
# need to repeatedly call it in your application:
Flasked.bottle_it
Add mapping
Furthermore you need to set up the mapping file:
# priv/flasked_env.exs
%{
my_flasked_app: %{
foo: {:flasked, :MY_FLASKED_APP_FOO},
bar: {:flasked, :MY_FLASKED_APP_BAR, :integer},
baz: [something: [nested: {:flasked, :MY_FLASKED_APP_BAZ, :dict}]]
}
}
So the placeholder has to be always a tuple in the following form:
{:flasked, :MY_FLASKED_APP_ENV_VAR_NAME} # defaults to string type
{:flasked, :MY_FLASKED_APP_ENV_VAR_NAME, :a_valid_type_atom}
Update config
Extend/modify your config/config.exs
:
config :flasked,
otp_app: :my_flasked_app,
map_file: "priv/flasked_env.exs" # must match with real file relative to the app's root directory
Run
Test and run your application:
MY_FLASKED_APP_FOO=some_foo_val \
MY_FLASKED_APP_BAR=42 \
MY_FLASKED_APP_BAZ=key:val,info=values_will_be_strings \
iex -S mix
In the console:
Application.get_env(:my_flasked_app, :foo)
#=> "some_foo_val"
Application.get_env(:my_flasked_app, :bar)
#=> 42
Application.get_env(:my_flasked_app, :baz)
#=> [something: [nested: [key: "val", info: "values_will_be_strings"]]]
The mapping file
This file is just a normal Elixir script file with a map as its content:
# priv/flasked_env.exs
%{
my_flasked_app: %{
key: {:flasked, :MY_FLASKED_APP_KEY},
another: {:flasked, :MY_FLASKED_APP_ANOTHER, :boolean},
port: {:flasked, :MY_FLASKED_APP_PORT, :integer, 4000},
},
another_app: [can: "be a dict, too"],
logger: %{
furthermore: "they do not need to have ENV placeholders",
but: "you can offload everything from config/*.exs here, if you really like to"
}
}
The application will fail to start if a placeholder was specified but the ENV var could not be found, unless you specify a default value.
About defaults and development
Use defaults rarely and wisely. Be more explicit, even in development mode.
To avoid manually providing every single env var for development, see [wrapper_example/](wrapper_example/) for a
Makefile based setup. (Just copy env.mk
and Makefile
into your project, adjust values and run make console
).
ENV Var placeholders
{:flasked, :MY_FLASKED_APP_KEY} # shortcut for string type without a default as fallback
{:flasked, :MY_FLASKED_APP_KEY, :boolean} # value type specified, no default given
{:flasked, :MY_FLASKED_APP_KEY, :integer, 1234} # value type and default specified
So the tuple must always have :flasked
as first element, an atom matching the ENV var you want to read, and optionally
a type and a default. If you want to give a default you always need to specify the type, even for strings.
Supported types
MY_FLASKED_APP_VAR=a_string_val
{:flasked, :MY_FLASKED_APP_VAR}
=> "a_string_val"
MY_FLASKED_APP_VAR=true
{:flasked, :MY_FLASKED_APP_VAR, :boolean}
=> true
- valid values: TRUE, true, FALSE, false
- any other value will always default to `false`
MY_FLASKED_APP_VAR=9
{:flasked, :MY_FLASKED_APP_VAR, :integer}
=> 9
MY_FLASKED_APP_VAR=3.1415
{:flasked, :MY_FLASKED_APP_VAR, :float}
=> 3.1415
MY_FLASKED_APP_VAR=list,of,strings
{:flasked, :MY_FLASKED_APP_VAR, :list}
=> ["list", "of", "strings"]
MY_FLASKED_APP_VAR=list,of,atoms
{:flasked, :MY_FLASKED_APP_VAR, :list_of_atoms}
=> [:list, :of, :atoms]
MY_FLASKED_APP_VAR=1,2,3
{:flasked, :MY_FLASKED_APP_VAR, :list_of_integers}
=> [1, 2, 3]
MY_FLASKED_APP_VAR=4.44,5.555,6.789
{:flasked, :MY_FLASKED_APP_VAR, :list_of_floats}
=> [4.44, 5.555, 6.789]
MY_FLASKED_APP_VAR=this:is,a:dictionary
{:flasked, :MY_FLASKED_APP_VAR, :dict}
=> [this: "is", a: "dictionary"]
MY_FLASKED_APP_VAR=one:1,two:2,three:3
{:flasked, :MY_FLASKED_APP_VAR, :dict_of_integers}
=> [one: 1, two: 2, three: 3]
More sophisticated types could be supported. You're welcome to contribute.