DSL for writing GraphQL in Elixir?

Would there be interest in a (small) DSL for writing graphql queries in Elixir?

In my tests I am now annoyed by the fact that GraphQL does not indent very well (writing gigantic GraphQL queries inside ~s(...)), so I’m tempted to write a macro which takes something like this:

    graphql = query [id: :string] do
      orders(a: id) do
        id
        title
        order_lines do
          id
          price
        end
      end
    end

And automagically converts it into this string:

query ($id: String) { orders(id: $id) { id title order_lines { id price } } }

@benwilson512 @bruce

1 Like

This is a good question. TBH I’m not sure it gets you much over using triple quotes:

query = """
query ($id: String) {
  orders(id: $id) { id title orderLines { id price } }
}
"""

GraphQL syntax is so very nearly a DSL on its own already. Certainly for tests I’m not sure that a DSL adds much value.

You’re right… the """ strings solve most issues. Except that it’s not smart with auto-indentation in the string. But I guess that’s an Emacs issue :wink:

1 Like

We just use triple quoted strings for queries and its working out pretty well. I’m not sure what the main benefits a DSL would offer over just using strings. There could be some benefit to an elixir, graphql client that provided introspection, type hints, and some sort of query validation though.

Heck yes! I’ve been wanting one for a while! I’ve just been writing strings so far, not got around to trying to make a DSEL yet. ^.^

Doing it in Elixir might be a bit more verbose, but if the DSEL is designed well then it could catch a lot of bugs at compile-time, especially if it introspects an Absinthe schema to verify against. ^.^

I hear you, but I actually think a sigil would be the best thing for that IE

query = ~A"""
query ($id: String) {
  orders(id: $id) { id title orderLines { id price } }
}
"""

Having actual graphql docs in tests has provided me with tons of utility because I can just directly link to test cases when other developers ask for examples. Obviously GraphiQL is a good exploration tool too, but it’s been pretty handy to have a full set of tested docs ready for usage.

Yes, it would indeed validate the given schema.

I’ve made some progress on this, I’ll extract it from my current code base and put it in a repo.

Actually, I wonder about combining the ideas.

What about a text definition (via “”") but it calls absinthe at compile-time to validate it is a valid ~schema~/call (does absinthe have a way to validate a call without actually calling it?).

Absinthe works a lot like a compiler, so you just build a pipeline of phases up prior to the actual resolution point:

validation_pipeline = schema
|> Absinthe.Pipeline.for_document(jump_phases: false)
|> Absinthe.Pipeline.before(Absinthe.Phase.Document.Execution.Resolution)

error_result_pipeline = [Absinthe.Phase.Document.Result]

case Absinthe.Pipeline.run(document, pipeline) do
  {:ok, blueprint, _} -> :ok
  {:error, blueprint, _} ->
    {:ok, %{result: result}, _} = Absinthe.Pipeline.run(blueprint, error_result_pipeline)
    {:error, result}
end

It isn’t quite as easy as I’d like. I’m gonna add a phase I think that will automatically run the result phase ONLY on error. Either way, this should get you going for now.

I’ve put it up: https://github.com/arjan/absinthe_dsl/
Works like this:

    query = query(arg: :string) do
      users(id: arg) do
        name
      end
    end

    assert query == "query ($arg: String) { users(id: $arg) { name } }"

Contributors welcome :slight_smile:

2 Likes

Meant a valid query, not schema. ^.^;

lol I hit enter too early. Fixed now with a real reply.

Ooo, that is awesome, being able to run that will be fantastic for verifying good strings at compile-time and no doubt for a DSEL too. :slight_smile:

Yeah your DSL just needs to build a blueprint tree. See the Draft protocol in Absinthe.

1 Like

I’d stayed away from generating queries dynamically primarily from this advice about the benefits of static graphql queries.

But this has me re-thinking. Tooling support and compile time checks are really appealing. This code is really nice to read.

Not sure what conclusion I’ll come to, but awesome work.

1 Like

This is the main benefit of github’s graphql-client: https://github.com/github/graphql-client. It validates your queries when you define them which is about as close as you can get to a “compile time” check in ruby.

If a DSL could be incorporated into absinthe then that seems great. Ideally you could use any schema. My use case is less about testing and more about interacting with external services though.

1 Like

Mine is more about calling into the locally defined absinthe system.

Yes that would be awesome. I see that Sangria has a graphql macro as well to check the query compile-time.

1 Like