Created
July 19, 2016 23:00
-
-
Save bitwalker/a4f73b33aea43951fe19b242d06da7b9 to your computer and use it in GitHub Desktop.
Useful config wrapper for Elixir
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Config do | |
@moduledoc """ | |
This module handles fetching values from the config with some additional niceties | |
""" | |
@doc """ | |
Fetches a value from the config, or from the environment if {:system, "VAR"} | |
is provided. | |
An optional default value can be provided if desired. | |
## Example | |
iex> {test_var, expected_value} = System.get_env |> Enum.take(1) |> List.first | |
...> Application.put_env(:myapp, :test_var, {:system, test_var}) | |
...> ^expected_value = #{__MODULE__}.get(:myapp, :test_var) | |
...> :ok | |
:ok | |
iex> Application.put_env(:myapp, :test_var2, 1) | |
...> 1 = #{__MODULE__}.get(:myapp, :test_var2) | |
1 | |
iex> :default = #{__MODULE__}.get(:myapp, :missing_var, :default) | |
:default | |
""" | |
@spec get(atom, atom, term | nil) :: term | |
def get(app, key, default \\ nil) when is_atom(app) and is_atom(key) do | |
case Application.get_env(app, key) do | |
{:system, env_var} -> | |
case System.get_env(env_var) do | |
nil -> default | |
val -> val | |
end | |
{:system, env_var, preconfigured_default} -> | |
case System.get_env(env_var) do | |
nil -> preconfigured_default | |
val -> val | |
end | |
nil -> | |
default | |
val -> | |
val | |
end | |
end | |
@doc """ | |
Same as get/3, but returns the result as an integer. | |
If the value cannot be converted to an integer, the | |
default is returned instead. | |
""" | |
@spec get_integer(atom(), atom(), integer()) :: integer | |
def get_integer(app, key, default \\ nil) do | |
case get(app, key, nil) do | |
nil -> default | |
n when is_integer(n) -> n | |
n -> | |
case Integer.parse(n) do | |
{i, _} -> i | |
:error -> default | |
end | |
end | |
end | |
end |
FWIW - I'd prefer to see this land in the equivalent Erlang code (http://erlang.org/doc/apps/kernel/application.html#get_env-1) which should enable 12FA-style config of any app, whether it's running Elixir or Erlang modules.
I often group configs with common domain, so I also had to get nested config values, use following code:
def get_config(app, path, default \\ nil) do
[root | subkeys] = List.wrap(path)
root_val = Application.get_env(app, root)
val = Enum.reduce(subkeys, root_val, fn (subkey, val) ->
case val do
nil -> nil
keyword when is_list(keyword) -> Keyword.get(keyword, subkey)
map when is_map(map) -> Map.get(map, subkey)
end
end)
get_config_val(val || default)
end
def get_config_val({:system, varname}), do: System.get_env(varname)
def get_config_val(val), do: val
So, to get :domain
in this config:
config :my_app, MyApp.MailingService.Client,
api_key: {:system, "MAILGUN_API_KEY"},
domain: {:system, "MAILGUN_DOMAIN"}
I'd do following inside MyApp.MailingService.Client
:
def process_url(path) do
"https://api.mailgun.net/v3/" <> get_config(:my_app, [__MODULE__, :domain]) <> path
end
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@bitwalker awesome gist! 👏
I noticed that we share a similar boilerplate code on a lot of our projects.
To avoid copy/paste errors, I've tried to to wrap it into a installable dependancy.
I hope someone else will find it useful as well: https://github.com/renderedtext/ex-config.
I also encourage @bitwalker to open a PR for elixirlang. I would really like it if this would be the default in elixir.