The solution

After Facebook delivered conference talks and writings about GraphQL and its rationale, we were confident the technology would serve as an elegant way of improving our services. There was an issue, though: we’re a Clojure team. At the time, GraphQL didn’t have a good story for Clojure. Luckily, GraphQL has a robust specification, so we set out to build our own fully realized implementation — Lacinia.

The GraphQL specification is immensely important to us. Our philosophy is that our library needs to speak and understand GraphQL as a lingua franca and have established execution semantics, but we’re striving for an idiomatic solution that works best within the Clojure ecosystem. One example of this philosophy is to be as data-driven as possible: the schema definition that declares a GraphQL server’s capabilities is written in EDN and uses Clojure data structures. Manipulating this data structure with Clojure code is not only supported, it is encouraged.

Meanwhile, the execution of GraphQL queries using Clojure is very natural. GraphQL, in essence, is a very functional approach: a filtering and transformation process that starts with all possible data and narrows to just the client’s requested results. Clojure’s use of pure functions and persistent data structures ensures these operations are safe and efficient.

After developing an internal version of Lacinia, we were able to deprecate nearly all of our existing APIs and onboard current and future clients onto our GraphQL-powered services. When you open your Walmart store receipts on your phone or visit samsclub.com and view your receipts on the web, you’re being served by Lacinia. If you use Walmart Grocery, you’re using Lacinia.

We designed our schemas around our data models and clients can simply ask for what they need. Of course, we can’t know all possible use-cases, but when a client tells us they can’t query for what they want, we can can typically add the missing field or relationship, and deploy it in a matter of minutes. Often, our internal data model already includes the information, and it’s only a matter of updating the schema to expose the new field. Because clients control what data they see, adding new fields and types to an existing schema is always safe and always backwards compatible.

Not only that, everything in the schema is fully discoverable and documented through introspection. We serve an instance of the GraphiQL (with an i!) web-based IDE: this allows developers on other teams to interactively build and execute queries. Lacinia automatically implements the introspection parts of the GraphQL specification; all we have to do is include user-facing documentation on fields and types.

Previously, when assisting other teams, we would throw around ad hoc curl commands, and it was always a challenge reproducing our client’s problems. Today, we pass around a GraphiQL link which can include the entire query — instant reproducibility.

The vast majority of the time, onboarding a new client to our service is just a matter of giving them the URL for GraphiQL, and they can quickly and interactively sketch out their queries and learn about all the fields and types through the interface. If they have problems or questions, they can send us their problematic queries. A surprising offshoot of this is how much I, as a developer of the service, have come to rely on GraphiQL for my own daily workflow: it’s faster and easier to build a GraphQL query than it is to access the underlying Cassandra database directly. GraphiQL, on top of GraphQL, constitutes an exceptionally powerful tool.

We think clojure.spec is the future of robust Clojure systems. Lacinia embraces clojure.spec and strives to leverage it throughout. For instance, custom scalars are defined using conformers. In order to remain on Clojure 1.8 stable while Clojure 1.9 iterates through various alpha versions, we’ve pulled in clojure-future-spec, a backport of the various clojure.spec features available to Clojure 1.9.