elixir-toniq / vapor

Runtime configuration system for Elixir
MIT License
596 stars 37 forks source link

Configuring based on the Mix environment #78

Closed QuinnWilton closed 4 years ago

QuinnWilton commented 4 years ago

What's the most idiomatic way of using the Mix environment (dev, prod, test, etc) to configure the application?

For context, I'm using Vapor to perform some lightweight dependency injection, where I can either call out to real external services, or swap out their clients with mock implementations for tests, using code approximately like this:

    providers = [
      %Vapor.Provider.Env{
        bindings: [
          {:mock_backend_services?, "MOCK_SERVICES", default: "true"}
        ]
      }
    ]

    translations = [
      mock_services?: fn s -> Mix.env() == :test or String.downcase(s) == "true" end
    ]

I want to always use my mock implementations in tests, but should be able to control which implementation to use in all other contexts (using environment variables, etc). Obviously that call to Mix.env() doesn't work, because Mix isn't available in releases. Since I'd like to be able to use my real services or my mock services in development, but always use the mock implementations in tests, it would be nice to have that case automatically handled without needing to change any configuration files or environment variables.

I can work around this by defining a configuration provider that pulls from Application.get_env, so that some environments (like test) are able to overwrite other configuration providers.

Is this the most idiomatic way of accomplishing what I want? Would such a configuration provider be worth including in Vapor? If so, I'm happy to clean up what I have and pull request it to the project.

keathley commented 4 years ago

One way that I've gotten around this before is to define a module attribute like @env Mix.env(). You can then use it like so: if @env && @env == :test, do: # stuff.... This is reasonably safe because it'll be set during compilation and should still work in a release.

QuinnWilton commented 4 years ago

That's a great idea! That'll definitely work for my use-case, and is preferable to polluting the global application config.

Thank you!

keathley commented 4 years ago

closing this for now.