Does your Elixir application call into a GraphQL API?
If so,
- Do you write GraphQL queries in raw strings?
- Are you ever uneasy about whether you’re interpolating arguments securely?
- What if it were dead simple to modify GraphQL queries programmatically?
Enter GraphQLDocument:
GraphQLDocument.to_string(query: [
human: {
[id: "1000"],
[:name, :height]
}
])
# Result:
"""
query {
human(id: "1000") {
name
height
}
}
"""
GraphQLDocument allows you to generate valid GraphQL code using Elixir primitives, to unlock a new set of possibilities when working with GraphQL APIs in Elixir.
A Quick Primer on the Syntax
GraphQL syntax involves specifying lists of field names:
name
age
height
Naturally, to emit a list of field names, you provide a list of atoms (or strings):
[:name, :age, :height]
GraphQL queries can get pretty nested, to request multiple layers of related data.
me {
notification_count
friends {
name
email
posts {
topic
body
}
}
}
This mixture of “primitive” fields (e.g. string, integer) and “object” fields (those with sub-fields) maps nicely to Elixir’s keyword list syntax. It’s valid in Elixir to create a regular list, but to end it with keyword pairs. To emit the above GraphQL snippet, you’d input:
[me: [
:notification_count,
friends: [
:name,
:email,
posts: [
:topic,
:body
]
]
]]
Lastly, in GraphQL you often want to pass arguments (“args”) into a field:
library(type: "hex", name: "graphql_document") {
downloads
dependencies {
name
url
}
}
To do that in GraphQLDocument, you wrap the args and “sub-fields” in an {args, fields}
tuple, like this:
[library:
{
[type: "hex", name: "graphql_document"],
[
:downloads,
dependencies: [:name, :url]
]
}
]
The documentation goes into more detail.
This syntax is a bit “heavier” than plain GraphQL syntax. But it was designed to “flow” similarly to GraphQL. Hopefully that makes it easy to follow. (Constructive criticism is welcome!)
Also, using this slightly “heavier” syntax opens up new possibilities, such as the Elixir compiler catching syntax errors, or using this library to create even more sophisticated tooling. On my team, we’ve done just that. I hope to release some of that tooling in the near future.