Skip to content

webdeb/confex

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Confex

Deps Status Hex.pm Downloads Latest Version License Build Status Coverage Status Ebert

This is helper module that provides a nice way to read environment configuration at runtime. It's inspired by Phoenix {:system, value} definition for HTTP port.

Installation

It's available on hex.pm and can be installed as project dependency:

  1. Add confex to your list of dependencies in mix.exs:
def deps do
  [{:confex, "~> 2.0.0"}]
end
  1. Ensure confex is started before your application:
def application do
  [applications: [:confex]]
end

Usage

  1. Defining configurations

Define your configuration in config.ex of your application.

config :ap_cfpredictor, AssetProcessor.AMQP.Producer,
  queue: [
    name:        {:system, "OUT_QUEUE_NAME", "MyQueueOut"},
    error_name:  {:system, "OUT_ERROR_QUEUE_NAME", "MyQueueOut.Errors"},
    routing_key: {:system, "OUT_ROUTING_KEY", ""},
    durable:     {:system, "OUT_DURABLE", false},
    port:        {:system, :integer, "OUT_PORT", 1234},
  ],

List of supported formats:

  • var - any bare values will be left as-is.
  • {:system, "ENV_NAME", default} - read string from system ENV, return default if it's nil.
  • {:system, "ENV_NAME"} - read string from system ENV, returns nil if environment variables doesn't exist.
  • {:system, :string, "ENV_NAME", default} - same as {:system, "ENV_NAME", default}.
  • {:system, :string, "ENV_NAME"} - same as {:system, "ENV_NAME"}.
  • {:system, :integer, "ENV_NAME", default} - same as {:system, "ENV_NAME", default}, but will convert value to integer if it's not nil. Default value type will not be changed.
  • {:system, :integer, "ENV_NAME"} - same as {:system, :integer, "ENV_NAME", nil}.
  • {:system, :boolean, "ENV_NAME", default} - same as {:system, "ENV_NAME", default}, but will convert value to boolean if it's not nil. Default value type will not be changed.
  • {:system, :boolean, "ENV_NAME"} - same as {:system, :boolean, "ENV_NAME", nil}.
  • {:system, :atom, "ENV_NAME"}
  • {:system, :atom, "ENV_NAME", :default}
  • {:system, :module, "ENV_NAME"}
  • {:system, :module, "ENV_NAME", Default}
  • {:system, :list, "ENV_NAME"} - same as {:system, :list, "ENV_NAME", nil}.
  • {:system, :list, "ENV_NAME", Default} - same as {:system, "ENV_NAME", default}, but will convert value to list if it's not nil, splitting at commas. Default value type will not be changed.
  1. Reading configuration

Read string values:

iex> Confex.get(:myapp, MyKey)
"abc"

Read integer values:

Confex.get(:myapp, MyIntKey)
123

Read map values:

Confex.get_map(:myapp, MyIntKey)
[a: 123, b: "abc"]
  1. Using macros

Confex is supplied with helper macros that allow to attach configuration to specific modules of your application.

defmodule Connection do
  use Confex, otp_app: :myapp
end

Connection in this case will read configuration from app :myapp with key Connection. Also it will provide helper function config/0 that will return values at run-time.

  1. Configuration validation

Sometimes you want to validate configuration, for this you can define def validate_config(config) method, that will be called on each config/0 usage.

Confex doesn't give opinions on a validator to be used in overrided methods.

Integrating with Ecto

Ecto has a init/2 callback, you can use it with Confex to read environment variables. We used to have all our repos to look like this:

defmodule MyApp do
  use Ecto.Repo, otp_app: :my_app

  @doc """
  Dynamically loads the repository configuration from the environment variables.
  """
  def init(_, config) do
    url = System.get_env("DATABASE_URL")
    config = if url,
      do: Keyword.merge(config, Ecto.Repo.Supervisor.parse_url(url)),
      else: Confex.process_env(config)

    unless config[:database] do
      raise "Set DB_NAME environment variable!"
    end

    unless config[:username] do
      raise "Set DB_USER environment variable!"
    end

    unless config[:password] do
      raise "Set DB_PASSWORD environment variable!"
    end

    unless config[:hostname] do
      raise "Set DB_HOST environment variable!"
    end

    unless config[:port] do
      raise "Set DB_PORT environment variable!"
    end

    {:ok, config}
  end
end

Integrating with Phoenix

  1. Set on_init callback in your prod.exs:

    config :my_app, MyApp.Web.Endpoint,
      on_init: {MyApp.Web.Endpoint, :load_from_system_env, []}
  2. Add load_from_system_env function to your endpoint:

    defmodule Mithril.Web.Endpoint do
    
      # Some code here
    
      @doc """
      Dynamically loads configuration from the system environment
      on startup.
    
      It receives the endpoint configuration from the config files
      and must return the updated configuration.
      """
      def load_from_system_env(config) do
        config = Confex.process_env(config)
    
        unless config[:secret_key_base] do
          raise "Set SECRET_KEY environment variable!"
        end
    
        {:ok, config}
      end
    end

Configuration priorities

By using Confex macro in your module, you allow to provide compile-time defaults for it.

  1. Declare module
defmodule MyModule do
  use Confex
end
  1. Provide defaults when using it
use MyModule,
  otp_all: :myapp,
  host: {:system, "HOST"}

This configs will overwritten by any configuration that you have in your application env.

Helpful links

About

Useful helper to read and use application configuration from environment variables.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • Elixir 99.5%
  • Shell 0.5%