Reading Environment Variables
View SourceThe Nvir.env!/1
, Nvir.env!/2
and Nvir.env!/3
functions allow you to load
an environment variable and cast it to the appropriate type by passing an
optional caster:
import Nvir
# This will raise if the variable is not defined
host = env!("HOST")
# This will raise if the variable is not defined or is empty
host = env!("HOST", :string!)
# This will use a default value if the variable is not defined, or otherwise
# convert the value to an integer.
port = env!("PORT", :integer!, 4000)
Requiring a variable
To fetch a variable, call env!/2
with the variable name and an optional
caster. A caster is either a built-in caster (given as an atom) or a custom
caster. See later for a description of both.
env!("PORT", :integer!)
This will attempt to fetch the variable as in System.fetch_env!("SOME_KEY")
, cast its value to an integer and return that value.
Two exceptions may be raised from that call:
System.EnvError
if the variable is not defined.Nvir.CastError
if the cast fails.
If no caster is given, Nvir will use the :string
caster:
env!("HOST")
Environment variables are always strings, so the :string
caster will return
the value as-is, given it is defined.
Default values
Use env!/3
to provide a default value.
Default values are not used when a variable is found, even if the cast fails, if the variable is empty, or whatever.
env!("PORT", :integer!, 4000)
Default values are not validated by the caster:
# :infinity is not a valid integer but this works
env!("TIMEOUT", :integer!, :infinity)
Built-in Casters
Built-in casters are defined as atoms. There are three flavors that behave differently when an environment variable value is an empty string.
- Casters suffixed with
!
like:integer!
or:string!
will raise if the variable contains an empty string. - Casters suffixed with
?
like:integer?
or:string?
will convert empty strings tonil
instead of casting. - Casters without a suffix exist for types that can be cast from an empty
string, i.e.
:string
,:atom
,:existing_atom
and:boolean
.
See below for a complete list of built-in casters and custom casters.
Empty strings occur when a variable is defined without a value:
HOST=localhost # value is "localhost"
PORT= # value is ""
Remember, as long as the key exists, the default value is never used; this holds true for empty string values.
With PORT=""
in the environment:
- Calling
env!("PORT", :integer!, 4000)
will raise because""
can't be cast to an integer. - Calling
env!("PORT", :integer?, 4000)
will returnnil
.
String Casters
Caster | Description |
---|---|
:string | Returns the value as-is. |
:string? | Converts empty strings to nil . |
:string! | Raises for empty strings. |
Boolean Casters
Caster | Description |
---|---|
:boolean | "false" , "0" and empty strings become false , any other value is true . Case insensitive. It is recommended to use :boolean! instead. |
:boolean! | Accepts only "true" , "false" , "1" , and "0" . Case insensitive. |
Number Casters
Caster | Description |
---|---|
:integer! | Strict integer parsing. |
:integer? | Like :integer! but empty strings becomes nil . |
:float! | Strict float parsing. |
:float? | Like :float! but empty strings becomes nil . |
Atom Casters
Caster | Description |
---|---|
:atom | Converts the value to an atom. Use the :existing_atom variants when possible. |
:atom? | Like :atom but empty strings becomes nil . |
:atom! | Like :atom but rejects empty strings. |
:existing_atom | Converts to existing atom only, raises otherwise. |
:existing_atom? | Like :existing_atom but empty strings becomes nil . |
:existing_atom! | Like :existing_atom but rejects empty strings. |
Note that using :existing_atom
with empty strings will not raise an exception
because the :""
atom is valid and is generally defined by the system on boot.
Deprecated casters
Those exist for legacy reasons and should be avoided. They will trigger a runtime warning when used.
In some languages, using null
where a number is expected will cast the value
to a default type value, generally 0
and +0.0
for integers and floats.
This behaviour does not exist in Elixir so casters for such types behave the
same with-or-without the !
suffix. This means :integer
and :float
will
raise for empty strings.
Caster | Description |
---|---|
:boolean? | Same as :boolean . ⚠️ Returns false instead of nil for empty strings. |
:integer | Same as :integer! . |
:float | Same as :float! . |
Custom Casters
The second argument to env!/2
and env!/3
also accepts custom validators
using an anonymous function. The given function must return {:ok, value}
or
{:error, message}
where message
is a string.
env!("URL", fn
"https://" <> _ = url -> {:ok, url}
_ -> {:error, "https is required"}
end)
It is also possible to return errors from Nvir.Cast.cast/2
. (Those are not
strings but they are properly handled.)
env!("PORT", fn value ->
case Nvir.Cast.cast(value, :integer!) do
{:ok, port} when port > 1024 -> {:ok, port}
{:ok, port} -> {:error, "invalid port: #{port}"}
{:error, reason} -> {:error, reason}
end
end)