Formatting GraphQL in Elixir projects

With the release of Elixir 1.13 it became possible to add plugins to the formatter. These plugins gives developers the option to hook into the Elixir formatter.

I've created an Elixir formatter plugin to Absinthe to format GraphQL documents. With the release of Absinthe 1.7 this is available for everyone to use.

To start, you'll need Absinthe 1.7 or higher together with Elixir 1.13 or higher.

The Absinthe project comes with Absinthe.Formatter, this is the default module you can add as a plugin. You can add it to your project as follows:

#.formatter.exs
[
  plugins: [Absinthe.Formatter],
  import_deps: [:ecto, :phoenix, :absinthe],
  inputs: ["*.{ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{ex,exs}", "{lib,priv,test}/**/*.{gql,graphql}"]
]

This will format .graphql and .gql files. Note, currently it only works for executable GraphQL documents. Documents with schema definitions will not render well.

However, if you use GraphQL-strings in your modules, e.g. in tests or in client api operations we can format those as well.

E.g. you have a test file containing a GraphQL query:

#simple_test.exs
defmodule SimpleTest do
  use ExUnit.Case

  @query """
  query test(
    $token:   String!) {
      user { name }
    }
  """

  test "some query" do
    assert {:ok, _} = Absinthe.run(@query, TestSchema)
  end
end

By introducing a custom sigil we can format @query module attribute. It's fairly simple. First we add a custom sigil, that does nothing but pass through the string. The below example adds the G sigil.

defmodule GraphqlSigil do
  @moduledoc """
  Adds the ~G sigil
  """
  def sigil_G(string, []), do: string
end

Next we add a custom formatter plugin matching on the custom G sigil. The format/2 passes through to the original Absinthe.Formatter

defmodule GraphqlFormatter do
  @behaviour Mix.Tasks.Format

  def features(_opts) do
    [sigils: [:G], extensions: []]
  end

  def format(contents, _opts \\ []) do
    Absinthe.Formatter.format(contents)
  end
end

Add the custom formatter to your .formatter.exs

#.formatter.exs
[
  plugins: [GraphqlFormatter],
  #...
]

Import and use the sigil in your testfile.

defmodule SimpleTest do
  use ExUnit.Case
  import GraphqlSigil

  @query ~G"""
  query test($token: String!) {
    user {
      name
    }
  }
  """
end

Now you can run mix format and it will format the strings with the G sigil. You may need to run mix compile before it works.

Photo by Viktor Jakovlev on Unsplash