💪 Scripting capabilities in non-standard GraphQL server

leoloso

Leonardo Losoviz

Posted on October 17, 2020

💪 Scripting capabilities in non-standard GraphQL server

This post was originally published on leoloso.com


Last week I made a proposal to add embeddable fields to GraphQL, but it didn't get a lot of support. I got the feedback that the extra complexity added to the server doesn't justify the benefits of this new feature, as in this comment on Reddit (which I replied to through this post).

My proposed feature then appears to be not about GraphQL as we know it nowadays, but about an über GraphQL, or what GraphQL could possibly be. That's either a problem, or an opportunity. In this write-up, Alan Johnson says:

[...] the execution model of GraphQL is in many ways just like a scripting language interpreter. The limitations of its model are strategic, to keep the technology focused on client-server interaction. What's interesting is that you as a developer provide nearly all of the definition of what operations exist, what they mean, and how they compose. For this reason, I consider GraphQL to be a meta-scripting language, or, in other words, a toolkit for building scripting languages.

I agree with this observation, but then I wonder: Where do these limitations start? What should be allowed, and what not? If any feature made GraphQL's scripting capabilities a bit more visible, gave a bit more control to the developer, and made the query a bit more powerful, should that be straightforward rejected? Or could it be given a chance?

Show me the stuff!

Let's talk business now. Here is something that GraphQL is not good at.

Say that you have a @translate directive that is applied on a String, as in this query:

{
  posts {
    id
    title @translate(from: "en", to: "es")
  }
}
Enter fullscreen mode Exit fullscreen mode

You cannot apply @translate on a field different than a String. If you need to, you must then create a new directive, which involves extra effort (often being ad-hoc) and pollutes the schema:

  • If a field returns [String], you'd need to create another directive @translateArrays

  • If only some entries from the array must be translated, you need to add an optional argument $keys: [String] to specify which keys to translate

  • If the keys are not strings, but are numeric, you need another argument $numericKeys: [Int] as to avoid type conflicts

  • If instead of an array, you get an array of arrays, you need yet another directive

And so on, concerning any random requirement from your clients.

As a result, the schema might eventually become unwieldy.


So, how could this situation be improved for GraphQL?

If GraphQL had capabilities to compose or manipulate fields, then a few elements could already satisfy all possible combinations.

GraphQL by PoP (the engine powering the recently launched GraphQL API for WordPress) is a GraphQL server because it respects the GraphQL spec, but is also a non-standard API server that provides other capabilities, including composable fields and composable directives.

Let's see how this server can satisfy all combinations described above, with just a few elements:

Notes:

  • GraphQL by PoP relies on the URL-based PQL syntax, so you can click on the links to execute the query and see its response
  • Field Root.echo is used to build the arrays
  • forEach and advancePointerInArray are directives that composes another directive

Translating posts as strings (run query):

posts.title<
  translate(from:en, to:es)
>
Enter fullscreen mode Exit fullscreen mode

Translating a list of strings (run query):

echo([
  hello,
  world,
  how are you today?
])<
  forEach<
    translate(from:en,to:es)
  >
>
Enter fullscreen mode Exit fullscreen mode

Translating only one element from the list of strings, with numeric keys (run query):

echo([
  hello,
  world,
  how are you today?
])<
  advancePointerInArray(path: 0)<
    translate(from:en,to:es)
  >
>
Enter fullscreen mode Exit fullscreen mode

Translating only one element from the list of strings, with keys as strings (run query):

echo([
  first:hello,
  second:world,
  third:how are you today?
])<
  advancePointerInArray(path:second)<
    translate(from:en,to:es)
  >
>
Enter fullscreen mode Exit fullscreen mode

Translating an array of arrays (run query):

echo([[
  one,
  two,
  three
], [
  four,
  five,
  six
], [
  seven,
  eight,
  nine
]])<
  forEach<
    forEach<
      translate(from:en,to:es)
    >
  >
>
Enter fullscreen mode Exit fullscreen mode

And so on, concerning any random requirement from your clients.

In my opinion, these features make the queries more powerful, and the schema more elegant. So they could be perfectly considered to be added to GraphQL.

Should consider adding extra scripting capabilities to GraphQL?

Bringing these additional scripting capabilities to GraphQL, wouldn't it be more valuable than not?

I understand that there is more complexity added to the server. But that's a one-time off. The GraphQL server maintainers can implement these features in a few months, and developers would be able to use them forever.

Isn't that a good tradeoff?

💖 💪 🙅 🚩
leoloso
Leonardo Losoviz

Posted on October 17, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related