Max Rukomoynikov

I love to create. Developer and designer. Looking forward to make cool things.

Trigger Phoenix controllers from mix tasks

On of my projects needs to receive files from outside, like for example being uploaded from Github CI and I'd like to simulate this behaviour on my local machine. So, I needed a mix task which I will trigger and it would upload a file to the application.

Easiest way would be to start the application in one terminal tab and trigger this mix task in another.But Phoenix has all needed to make these both tasks simultanesly. In other words mix tasks can start up your application and shut it down when it's finished.

Application part

defmodule AppForArticleWeb.PageController do
  use AppForArticleWeb, :controller

  def home(conn, %{"id" => id}) do
    text conn, "Showing id #{id}"
  end
end

Just for the sake of explanation I will keep it simple. Just a controller action that accepts get request with one query parameter.

Mix task

defmodule Mix.Tasks.UploadDevReport do
  use Mix.Task

  @shortdoc "Uploads a development report to the local server"

  @impl Mix.Task
  def run(_args) do
    start_backend()

    %Req.Response{body: body} = Req.get!("http://localhost:4000?id=1")

    IO.puts(body)
  end

  defp phoenix_running?(address, port) do
    case :gen_tcp.connect(to_char_list(address), port, [:binary, active: false], 1000) do
      {:ok, _} -> true
      {:error, _} -> false
    end
  end

  defp start_backend do
    case phoenix_running?("localhost", 4000) do
      false ->
        Application.put_env(:phoenix, :serve_endpoints, true, persistent: true)
        Mix.Task.run("app.start", [])
      true ->
        Mix.Task.run("app.start", [])
    end
  end
end

The mix task itself is relatively simple as well. I just check if TCP server is running. If not it starts the application. Main part is taken from the Phoenix github repo.