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.EnvErrorif the variable is not defined.Nvir.CastErrorif 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 tonilinstead of casting. - Casters without a suffix exist for types that can be cast from an empty
string, i.e.
:string,:atom,:existing_atomand: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)