Provider

hex.pmhexdocs.pmBuild Status

Provider is a library which helps managing the operator configuration of a system.

The term operator configuration refers to the settings which have to be provided by the operator of the system before the system is started. Typical examples include database credentials (host, database name, login, password), http and https ports, 3rd party API keys, and such. On the other hand, things such as Ecto database adapter, or dev/test-only variations such as mocks, are not a part of operator configuration.

Provider offers the following features:

Provider was born out of real need and is based on lessons learned and issues experienced with config scripts and app config. Provider doesn't use app config, and is instead only focused on fetching values from external sources, such as OS env. The responsibility of working with those values is left to the client.

Provider is currently used in a few small projects, but it's not exhaustively tested nor optimized. The API is not considered as stable, and it may change significantly. Provider currently only supports the features needed by the projects it powers. Therefore, it has a couple of limitations:

Tackling these shortcomings is on the roadmap, but it hasn't happen yet, because there was no actual need to address them so far.

Quick start

Add provider as a dependency:

defmodule MySystem.MixProject do
  # ...

  defp deps do
    [
      {:provider, "~> 0.1"},
      # ...
    ]
  end
end

Create a module where you'll consolidate your configuration:

defmodule MySystem.Config do
  use Provider,
    source: Provider.SystemEnv,
    params: [
      # The `:dev` option sets a dev/test default. This default won't be used in `:prod` mix env.
      {:db_host, dev: "localhost"},

      # The `:test` option overrides the default in the test mix env.
      {:db_name, dev: "my_db_dev", test: "my_db_test"},

      # The `:default` option sets a default in all mix envs, which means that this setting is
      # optional.
      #
      # Owing to `type: :integer`, the external input will be converted into an integer. An error
      # will be raised if this conversion fails.
      {:db_pool_size, type: :integer, default: 10},

      # ...
    ]
end

Validate configuration during app startup:

defmodule MySystem.Application do
  use Application

  def start(_type, _args) do
    children = [
      MySystem.Config
    ]

    # ...
  end

  # ...
end

Use config module functions to fetch the values:

defmodule MySystem.Repo do
  use Ecto.Repo,
    otp_app: :my_system,
    adapter: Ecto.Adapters.Postgres

  @impl Ecto.Repo
  def init(context, config) do
    Provider.ecto_config(MySystem.Config, context, fn ->
      {:ok,
        Keyword.merge(
          config,
          hostname: MySystem.Config.db_host(),
          database_name: MySystem.Config.db_name(),
          pool_size: MySystem.Config.db_pool_size(),
          # ...
        )
      }
    end)
  end
end

Invoke MySystem.Config.template() in prod Mix env to generate a .env template with all configuration parameters. The function will return a string which you can print to screen or save to a file.

Alternatives

There are a couple of other libraries available with similar features:

License

MIT