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