Can I connect to my phoenix endpoint within a custom mix task?

I have an Absinthe GraphQL API and VueJS + Apollo app as a single Phoenix application. I need to dynamically generate the fragmentTypes.json file in order for my Apollo clients to utilize my Interface and Union types. I’ve created a custom mix task that posts the appropriate schema query, but I have to have my phoenix app running in order to connect to it. Is it possible within my mix tasks to start the phoenix app so that I can connect to it?

Ultimately, this should all happen within my CI/CD pipeline. Here’s what I have now as a starting point.

defmodule Mix.Tasks.Gql.GenerateFragmentTypes do
  @moduledoc """
  Generates the GraphQL Type information to support Apollo's IntrospectionFragmentMatcher

  See: https://www.apollographql.com/docs/react/data/fragments/#fragments-on-unions-and-interfaces
  """
  use Mix.Task

  @shortdoc """
  Generates the GraphQL Type information.
  """
  def run(args) do
    # TODO: url & output file path from args
    [url, path] = [to_charlist("http://localhost:4000/graphql"), "./fragmentTypes.json"]
    
    # TODO: Fire up the app so we can query the GraphQL API
    # {:ok, _} = Application.ensure_all_started(:my_phoenix_app)
    :ok = Application.ensure_started(:inets)

    # Create the schema query we need to get the GraphQL Types
    query =
      Jason.encode!(%{
        query: """
        query {
          __schema {
            types {
              kind
              name
              possibleTypes {
                name
              }
            }
          }
        }
        """
      })

    # POST query to the provided GraphQL url
    {:ok, {_, _, body}} = :httpc.request(:post, {url, [], 'application/json', query}, [], [])

    # Filter only the types we care about
    types =
      Jason.decode!(body)
      |> get_in(["data", "__schema", "types", Access.all()])
      |> Enum.reject(fn %{"possibleTypes" => types} -> is_nil(types) end)

    # Put them into a JSON document & output it
    content =
      Jason.encode!(%{
        __schema: %{
          types: types
        }
      })

    File.write(path, content)
  end
end

No need to fire up a phoenix server:

query =  """
        query {
          __schema {
            types {
              kind
              name
              possibleTypes {
                name
              }
            }
          }
        }
        """

{:ok, %{data: result}} = Abinthe.run(query, MySchema)

You can inspect result and JSON encode it and dispatch it to your frontend.

1 Like

Thanks, @samba6! This does exactly what I needed.