GraphQL has a certain, almost hidden feature in it, that is of critical importance to me. It's mentioned in the documentation, but I think many people breeze past that page in the excitement of everything else GraphQL has to offer.
Before I reveal what this feature is, let me explain some of my personal history and how it relates.
Back in the early naughts, I created an open-source, server-side Java web framework, Apache Tapestry. I'm proud of many unique features of Tapestry that were forward thinking at the time, even if such features are now considered quite essential. Even so, I often struggled at the "elevator pitch" for why Tapestry was so valuable.
Eventually, I came up with four essential aspects of Tapestry that drove its design and served to highlight what was uniquely useful about it: Simplicity, Consistency, Efficiency, and Feedback.
Simplicity at the time was essentially conciseness and hiding some of the necessary machinery. Thanks to Rich Hickey, my exact definition of simplicity has shifted subsequently.
Consistency concerned being able to use the same techniques in different related areas: in Tapestry, creating a page, a component that can be reused within the same application, or a component that can be reused across applications were virtually identical.
Efficiency concerned the overhead of using the framework; essentially, the beneficial features of Tapestry had to be deliverable with very good performance. In fact, Tapestry (despite doing far more per-request work than many competing frameworks) was always in the top-tier, performance-wise.
And that leaves Feedback, and its rather vague definition. Feedback, to my mind, covers many things within the general job of making the developer's life bearable. One aspect was that Tapestry supported live changes to code and templates, thus streamlining the developer's feedback loop: being able to see a change as soon as you refreshed a page, rather than in tens of seconds or longer (sometimes much, much longer) was quite liberating, even before the ever-present distraction of Twitter threatened to break your concentration while you waited.
But, at its core, Feedback was a commitment throughout the code to catch common errors and report them with as much detail as possible; as well as a built-in detailed exception report page that provided a wealth of information, including stack traces and highlighted source lines from component templates.
The intent was that when anything went wrong, the details needed to quickly diagnose the problem was right in front of you. I spent a lot of time in Tapestry training and conference sessions triggering that exception report and digging through it, then quickly fixing things and continuing to the next step.
So, how does Feedback (as well as Simplicity, Consistency, and Efficiency) relate to GraphQL?
Simplicity: for all that GraphQL tacks a type system on top of queries and JSON, the overall design of GraphQL is deliberately simple. If simplicity is what allows you to easily understanding the behavior of your system, then GraphQL earns high marks.
Consistency: everything essential in implementing a GraphQL schema is a field (that may have arguments). Queries and mutations? Fields on a root Query or Mutation object. Subscriptions? Still a field. Input objects: still looking like fields (without arguments). A single type system defines input objects and field arguments as well as all output values. It's all very consistent.
Efficiency: A gain and a loss here; certainly it's more expensive computationally to parse and execute a GraphQL query than it is to route a request and spew out JSON; likewise, the fact that all GraphQL queries route through a single endpoint can be an impediment to traditional caching approaches.
However, some of these challenges can be mitigated by leveraging server-stored queries (the client sends up the name of a query, not the query itself) and the fact that the client requests only what's actually needed can make a significant difference in actual throughput, especially in terms of downloading data to mobile devices. Our GraphQL integration layers allow most content from backend systems to be filtered out before it goes over the wire; multi-kilobytes JSON payloads full of extraneous data is filtered down to a handful of output values, numbering in the dozens of characters, not thousands.
That leaves Feedback: GraphQL gets high marks here for its introspection capabilities, which make things like GraphiQL possible. But the specific aspect of feedback that prompted me to write this posting was input validation; GraphQL specifically discusses exactly how and when to capture all manner of problems in the GraphQL query, and exactly how those problems are to be reported back to the client. This includes unparsable query documents, references to unknown operations, fields, or arguments, omitting of required arguments, and even cases where the wrong scalar values (or improperly formatted scalar values) are provided.
In each of these cases, GraphQL can provide an error detailing exactly what went wrong, and pinpoint the exact location in the query document related to the failure.
By contrast, I'm working on integrating a piece of our application with another team's JSON-based API. We have to send a fairly large, deeply nested JSON object as the body of the request. If our code omits a field, includes an extra field, or provides any content that isn't exactly what the API expects, we get back the following:
That's it. No context, no indication of what underlying property of the request JSON is at fault, no clue as what to fix or how to proceed. No feedback.
At a very minimum, an equivalent GraphQL API would have identified precisely which field was executing when an error occurred, or which argument of which field had invalid or missing data. The error would be associated with a specific position within the input GraphQL query document. There would be a place for me to start in figuring out what went wrong.
So, that may itself be the secret sauce in GraphQL; it's not just that it's useful (simple, consistent, efficient) when everything is working well, but it's extra-useful, with feedback, when things go wrong.
Top comments (0)