Universe is betting big on GraphQL. We’ve been hard at work this quarter aiming to deliver a richly typed, documented, publicly available GraphQL interface into our existing event ticketing platform.

Today, we’re excited to announce general availability of our beta GraphQL API. You can explore this API with our handy GraphiQL Explorer and documentation.

In making this beta, and through the course of our early development, we’ve identified five compelling use cases for GraphQL that might be less obvious, but compelling to those new to this paradigm:

Strong client contracts Domain layer abstraction Typed request/response interfaces Expensive fields Documentation

Strong client contracts

Problem: Eventually, you will get tired of designing systems that introduce type impedence bugs between servers and clients. Universe has been very API-contract oriented since its inception. We’ve built several large-scale single page JavaScript apps including universe.com, and four mobile apps across two operating systems. Every single project encounters null is undefined type errors, when server APIs fail to produce responses that a client expected.

Solution: With the schema introspection provided by GraphQL, we can provide strong guarantees to clients about the format of our server responses. With tools like apollo-codegen , we can generate platform-specific type declarations for our client apps (Flow types for JavaScript, native types for Swift, etc). With type declarations for our API, we can eliminate entire classes of errors, where apps accidentally look for missing fields in JSON responses, producing runtime crashes.

Clients can also lint the queries they make by transforming stringified queries into the GraphQL AST (abstract syntax tree) and comparing it against the introspected schema. An NPM package, graphql-tag, lets us do this as a build step during Webpack preprocessing in our frontend JavaScript projects.

Here, for example, we see a query named DemoQuery , which accepts an argument of id , expecting that value to be typed as an ID scalar. The response to this query will be an object mapping the same structure of the query itself. With graphql-tag, we pre-process all of our queries by saving them in separate files with the *.graphql extension.

A second step with apollo-codegen reads our *.graphql files and produces matching Flow types for each query and its variables, like so:

With this type definition, we can make type assertions for props in React Components, or even just plain functions that transform this map into something else. Giving those functions a means of proving the type of their input or output makes our code resilient to the most common class of data error.

Domain layer abstraction

Problem: A fast-moving startup transitions between markets and its domain language gets taken along for the ride. Abstractions that made sense and sounded descriptive now leave developers scratching their heads. A mountain of legacy external-party commitments make boundary-area refactoring difficult.

Solution: Pave it over! GraphQL provides a way for us to abstractly layer new interfaces over our existing data structures. We don’t have to assume the same old business models are related in the same ways — we don’t even have to name them the same things.

For us, this create an opportunity for a fresh conceptual start while being able to maintain existing interface boundaries in legacy APIs indefinitely. This is a big deal because the Universe of 2011 has very different customer data needs from the Universe of 2017.

Typed Request/Response Interfaces

Problem: After building several versions of an API, we’ve created many different patterns, and followed different JSON API design trends. The structure of our responses varies: sometimes the payload is wrapped in a key like data or payload or message , often it has a complicated relationship sideloading strategy where each root key is an enumerable set of a type (this is internally known as Old School Active Model Serializers format, and mimics an early version of the JSON API spec). Our request interface is similarly fragmented: pagination strategies, search, and ordering all differ depending on API version, and our implementation strategy at the time of original development.

Solution: GraphQL gives us standardized, typed interfaces. Our response interface is designed according to a specification. Query responses are formatted as maps matching the structure of the query request, and returned in a key called data . Instead of needing to entity-map the response, we can predictably traverse the response given knowledge of only the query from the request. Similarly, errors are returned in a standardized format — locations , path , and message values for each error in the operation are returned are added to a root key called errors .

While GraphQL doesn’t, on its own, define a pagination interface, we’ve discovered compelling patterns defined in the Relay spec, and supported by popular GraphQL client SDKs in the wild.

Expensive Fields

Problem: With previous JSON API spec-inspired API designs, we found static model-based serializers to be a significant performance limitation. We have to be extra careful about excluding “expensive” fields from our responses given that a model can be serialized in the context of both a single resource (ex. /posts/1 ) and in the context of a set or list (ex. /posts ).

Solution: In GraphQL, each field on a type must be able to resolve to a value. The cost of each resolution is only incurred if a query actually requests the field. Previously, as is common in MVC-style web servers, our models would be marshalled into JSON by a view layer (objects commonly referred to as serializers). Fields that were expensive to render would have to be monitored diligently. With GraphQL, we can be much more permissive about per-field resolution costs.

Additionally, because each field is individually resolved we can instrument precise performance metrics. Apollo Optics collects this data for us out-of-box with effectively no configuration necessary:

Apollo Optics in action

Documentation

Problem: Developer friendliness is really important if you care about public adoption of your API. But unless you’re writing a public API deliberately, it’s easy for internal product teams to rely on folklore, Google Docs, and private Slack messages as functioning documentation, instead of high quality technical writing.

Solution: All GraphQL types support a description field according to the spec. Description is a field designated for use by implementers to describe the functionality of the field:

All types in the introspection system provide a description field of type String to allow type designers to publish documentation in addition to capabilities.

In our server implementation, we’ve taken advantage of this functionality to provide rich, English-language descriptions of all of the type objects in our system — right alongside our code. With this form of inline documentation in our schema, we can automatically generate developer-friendly docs. A number of GraphQL community projects exist which transform the description fields into navigable documentation. GraphiQL Explorer demonstrates this functionality nicely: