When I use your configuration, then try to access the key in a controller with:
Application.get_env(:app, App.Notifications)[:notification_api_key]
I get:
{:system, "API_NOTIFICATION_KEY"}
so phoenix is not looking up the env variable. On the other hand, if I manually set the key in the config, like this:
config :app, App.Notifications,
notification_api_key: 1234
then I get 1234
in the controller. I read something that said reading environment variables with {:system, "ENV_VAR"}
was going to be deprecated at some point, and I don't see any mention of :system
in the docs. I'm using phoenix 1.4.6
.
According to this article, you can define an init/2
function in endpoint.ex
, which will be called at run time--just before your phoenix app starts--which means you can directly look up environment variables at run time with System.get_env/1
. The init/2
function is described in the Phoenix.Endpoint docs:
Dynamic configuration
For dynamically configuring the endpoint, such as loading data from
environment variables or configuration files, Phoenix invokes the
init/2 callback on the endpoint, passing a :supervisor atom as first
argument and the endpoint configuration as second.
Here's an example that I came up with:
def init(:supervisor, config) do
#IO.inspect config, label: "config"
#IO.inspect Application.get_all_env(:app1), label: "all"
Application.put_env(:app1, :notification_api_key,
System.get_env("API_NOTIFICATION_KEY"),
persistent: true
)
{:ok, config}
end
Then in my controller:
key = Application.get_env(
:app1, App1.Notifications
)[:notification_api_key]
IO.inspect key, label: "key"
And, in the server window I see:
key: 1234
You should also realize that setting module attributes happens at compile time, so this line:
@api_notification_key Application.get_env(:app, App.Notifications)[:notification_api_key]
retrieves the env variable for the system on which the app is compiled.
I also tried setting a module attribute in my controller:
@attr Application.get_env(
:app1, App1.Notifications
)[:notification_api_key]
and init/2
defined in endpoint.ex as above, and in my controller @attr was nil--as expected. That's because at compile time, init/2
hasn't been called yet, so no value for :notification_api_key
has been set.
To me, it doesn't feel right calling Application.put_env()
in init/2
:
def init(:supervisor, config) do
Application.put_env(:app1, :notification_api_key,
System.get_env("API_NOTIFICATION_KEY"),
persistent: true
)
{:ok, config}
end
I think I should be doing something to config
. Here's another example:
def init(:supervisor, config) do
IO.inspect config, label: "config"
key = System.get_env("API_NOTIFICATION_KEY")
new_config = Keyword.put_new(config, :notification_api_key, key)
IO.inspect new_config, label: "inside init/2: new_config"
{:ok, new_config}
end
Then in my controller:
IO.inspect(
App1Web.Endpoint.config(:notification_api_key, :not_set),
label: "config"
)
In my server window, I see:
config: "1234"
so that works, too.