Conditional dependencies in mix.exs

I have a program which can provide different services, depending on its run-time configuration (through a configuration file or command-line options). Some of the services, but not all, depend on external libraries, such as HTTPoison, so I add in my mix.exs:

      {:httpoison, "~> 1.8"} 

But I would like to avoid this dependency (HTTPoison brings a lot of other libraries) if not necessary. How to make it conditional, and allow the program to know if it has been included or not, so it can produce a proper error message if the user tries to activate the service, without having the library?

I’ve read this StackOverflow post, which seems to be about a different problem, and this Elixir Forum discussion which was inconclusive.

There’s an optional option, though it’s meant more for dependencies within libraries, so the app using the library can choose to include it or not:

{:httpoison, "~> 1.8", optional: true} 

But maybe something like this:

def dep_enabled?(env_key), do: not is_nil(System.get_env(env_key))
def deps() do 
[{:httpoison, "~> 1.8", optional: dep_enabled?("POISON_IS_GOOD_FOR_YOU")} 
...

Actually, re-reading the docs it looks like in your case (if this is a top level app) it would always be included, so maybe a similar approach but using only to specify [:dev, :test] if the dep is disabled, and [:dev, :test, :prod] if it should be enabled?

1 Like

I think target is what you want.
In your mix.exs you would use it like:

{:httpoison, "~> 1.8", targets: :your_target_name}

and during build just set MIX_TARGET=your_target_name to build your application with httpoison.

I think during runtime you can check if httpoison was compiled via:

:application.info[:loaded]

It should appear in the list of loaded applications. Not sure if there is a more elegant way.

Unfortunately, the code cannot compile (“HTTPoison.Response.struct/0 is undefined”) so I also need a compile-time condition.

Yes, of course. I forgot to mention that.

You can do something like this:

defmodule SomeModule do
  if Mix.target() == :your_target_no do
    def some_function do
      HTTPoison.get("elixirforum.com")
    end
  else
    def some_function do
      # Do something without HTTPoison
    end
  end
end

Not sure if that suits your needs and how complex the httpoison integration is in your app.

1 Like