Changing Phoenix defaults for compile-time configuration?

I’ve built a light-weight API “monitoring endpoint” (a Phoenix project without Ecto, Brunch etc) that’s intended to be included as a dependency in other Phoenix projects. However, it seems that to get everything to work I have to do a bit of configuration in config.exs ofthe web application that uses the monitoring endpoint; things like…

config :monitoring_endpoint, MyOrg.Monitoring.Endpoint,
  http: [port: 5000],
  render_errors: [view: MyOrg.Monitoring.ErrorView, accepts: ~w(json)],
  server: true

I’m fine with setting the port, of course (every app will use a different one for its monitoring endpoint anyway), but… I really don’t think that setting up error rendering for the monitoring endpoint is a concern of the web application using it.

The reason it’s needed seems to be due to the default Phoenix setup, which…

  1. uses an HTML view
  2. incorrectly assumes that the view is called MyOrg.ErrorView

Can I somehow could have my monitoring endpoint override the compile-time defaults even when it’s being used as a dependency?

3 Likes

What I can think of off the top of my head is to provide eg. a Monitoring.configure(port: 5000) call, that would be usable from mix.exs in the web app using the monitoring endpoint, and would return all the necessary config items.

Or wait… Won’t even work, right? Since deps aren’t compiled yet at that point…

Answering my own question, for the specific case of the compile-time render_errors configuration, it seems after some investigation that one can simply make use of Phoenix.Endpoint.RenderErrors in the router of the Phoenix-based dependency, the monitoring endpoint in my case:

defmodule MyOrg.Monitoring.Router do
  use MyOrg.Monitoring.Web, :router
  use Phoenix.Endpoint.RenderErrors, view: MyOrg.Monitoring.ErrorView, accepts: ~w(json)

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/monitoring", MyOrg.Monitoring do
    pipe_through :api

    get "/status", StatusController, :index
  end
end

For any runtime configuration issues that might come up, the answer should be more straightforward; set desired defaults in the env section of the application configuration:

defmodule MyOrg.Monitoring.Mixfile do
  use Mix.Project
  # ...
  def application do
    [mod: {MyOrg.Monitoring, []},
     applications: [:phoenix, :phoenix_pubsub, :cowboy, :logger, :gettext],
     env: [some_config_key: "default value"]]
  end
  # ...
end
1 Like

I personally include a default config that the user can import_config into their own then override the default values with their own. I find it the easiest to do for both me and the user. ^.^

Interesting! Can you actually include a default config from within a dependency?

Yep, I just do things like this in my base config.exs file:

import_config "../deps/somedep/config/config.exs"

I wish all deps followed this pattern, then I could just do this:

import_config "../deps/*/config/config.exs"

EDIT: Err, you said ‘from within a dependency’? Technically I think you could, by doing this:

import_config "../../../config/blah.exs"

And of course you could conditionally test for it, grab it from the environment, whatever. A config.exs file is just normal elixir after all. ^.^

1 Like

Oh, of course… Didn’t think about that approach :slight_smile: Thanks!

Most likely I’ll prefer to set things up in the dependency itself so that it only needs configuration that’s relevant from the perspective of the app using the dependency – but if I run across something in Phoenix etc that I just can’t seem to get past, at least I’ll have another option in my toolbox to bring out!

1 Like