In my config I use helpers to give me more confidence that I get the environments variables:
import Config
################################################################################
# START HELPERS
################################################################################
#
# Getting environments values from the environment as it his now is flaky,
# because we may get a blank string " ", that will be accepted as valid value
# when using the recommended approach:
#
# ```
# System.get_env(var) || raise "blah blah"
# ```
#
# Also if an env var is assigned with double quotes around it's value, then
# `System.get_env(var)` will not strip them out, thus we end-up with an
# unexpected value in our application.
#
# Sometimes we also want to enforce that the value in the env var has a minimal
# length, like for secrets, thus I prefer to have this being enforced in the
# moment we fetch it.
#
blank? = fn
<<" " :: binary, rest :: binary>>, func -> func.(rest, func)
_string = "", _func -> true
_string, _func -> false
end
empty? = fn string -> blank?.(string, blank?) end
single_quoted? = fn string ->
("\'" === binary_part(string, 0, 1))
and ("\'" === binary_part(string, byte_size(string), -1))
end
double_quoted? = fn string ->
("\"" === binary_part(string, 0, 1))
and ("\"" === binary_part(string, byte_size(string), -1))
end
get_env = fn (var, min_length)
when is_binary(var) and is_integer(min_length) ->
case System.get_env(var) do
nil ->
raise "Missing value for var #{var} in your .env"
value when is_binary(value) ->
with false <- single_quoted?.(value),
false <- double_quoted?.(value),
false <- empty?.(value),
true <- byte_size(value) >= min_length
do
value
else
true ->
raise "#{var} value cannot be surrounded by single quotes: #{value}"
true ->
raise "#{var} value cannot be surrounded by double quotes: #{value}"
true ->
raise "#{var} cannot be empty"
false ->
raise "Value for env var #{var} needs to have a minimal length of: #{min_length}"
end
end
end
################################################################################
# END HELPERS
################################################################################
config :tasks,
ecto_repos: [Tasks.Repo]
# Configures the endpoint
config :tasks, TasksWeb.Endpoint,
url: [host: "localhost"],
secret_key_base: get_env.("SECRET_KEY_BASE", 255),
render_errors: [view: TasksWeb.ErrorView, accepts: ~w(html json)],
pubsub_server: Tasks.PubSub,
live_view: [
signing_salt: get_env.("LIVE_VIEW_SIGNING_SALT", 128)
],
session_options: [
store: :cookie,
key: "_tasks_key",
signing_salt: get_env.("SESSION_SIGNING_SALT", 128),
encryption_salt: get_env.("SESSION_ENCRYPTION_SALT", 128)
]
But I am not planning to use the default config flow config.exs > prod.exs > prod.secret.exs > releases.exs
, instead I am planning in use release.exs > config.exs
, that in dev becomes release.exs > config.exs > dev.exs
.
NOTE: I have not deploy yet with releases.exs, because this config flow is a work I have in progress now, thus it may not work for deploying with releases, but it works in development. I will let you know when a deploy with it.