GraphQL at Propel
At Propel, we use GraphQL extensively to enable our customers to communicate with us.
- Customers can connect their data with Propel using our API.
- They can execute real-time analytic queries using GraphQL.
- They can manage their account's resources using GraphQL API requests.
As you may imagine, Propel's GraphQL API is pretty big, and we want to keep it clean, maintainable, and well-documented as possible. Unfortunately, sometimes GraphQL does not make things easy for us:
- Common fields: While defining <span class="code-exp2">types</span>, we need to copy-paste all the common fields across a lot of resources, fields like <span class="code-exp2">id</span>, <span class="code-exp2">createdAt</span>, <span class="code-exp2">modifiedBy</span>...
- CRUD inputs: When defining <span class="code-exp2">inputs</span> that are meant to create or modify specific resources, there is a lot of repeated code for handling the <span class="code-exp2">input</span> that creates the resource vs. the one that modifies it.
- Cursor pagination: We follow the GraphQL Cursor Connections Specification, and for each paginated resource, we need to define its own <span class="code-exp2">Edge</span> and <span class="code-exp2">Connection</span> even though all look the same.
- Documentation: We document every field, and if there is a common field across different <span class="code-exp2">types</span> or <span class="code-exp2">inputs</span>, we need to maintain the documentation individually for each one.
All these problems can be boiled down to one: the lack of tools the GraphQL SDL specification provides for reusing code.
Using a code-first approach and auto-generating the GraphQL schema is a very common way to overcome this problem, but it has some disadvantages:
- For customer-facing schemas, it can get tricky to control and review exactly what is being served to the customers, as there is no direct control of the GraphQL schema.
- Ensuring that the documentation is consistent across all the resources is less ergonomic, as the documentation pieces are spread through the code base.
- Non-technical people find it more difficult to contribute to new API features, as they will need to deal with actual code (TypeScript, Python, GoLang...).
But what if there is another way?
GraphQXL is a language built on top of the GraphQL SDL syntax that solves the reusability problems of the original language.
It is framework-agnostic, as it is just an independent language that compiles down to plain GraphQL, that way it can be used with any programming language that supports it.
Here are some of GraphQXL’s features:
One common pattern is to have an <span class="code-exp2">interface</span> that defines some common fields that are shared across many types, for example, imagine that we want to reuse the field’s from this <span class="code-exp2">interface</span> across multiple types:
In GraphQXL spread operators can be used to solve this:
Try it in the GraphQXL explorer!
In GraphQL APIs there are usually some <span class="code-exp2">types</span> or <span class="code-exp2">inputs</span> that are very similar, and one clear example is the cursor-based pagination. Generics are really good at handling structures that look almost the same but have a small difference:
Try it in the GraphQXL explorer!
<aside>💡 Note that the documentation for the Edges and the Connections is also autogenerated following the templating rules in the source GraphQXL file.</aside>
There are different ways and tools developers can use to split a GraphQL schema into multiple files and merge them afterwards, but GraphQXL provides its own: import statements.
The behavior is pretty straightforward and predictable, given this file <span class="code-exp2">common-stuff.graphqxl</span>
It can be imported and reused into other <span class="code-exp2">.graphqxl</span> files:
A good usage of this feature could end up in a final .graphqxl that looks like this:
Is there more?
There is a lot more! Feel free to