GraphQL as a Microservices Routing Layer
Slicing up monolith applications into a suite of services introduces a set of engineering tradeoffs that must be considered. For example, what you gain process isolation can potentially cost you in operational overhead and complexity. What you gain in architectural flexibility costs can cost you in terms of cohesion. Reasoning about applications in a service-oriented architecture gets easier ‘in the small’ but more difficult ‘in the large’.
There exists a great variety of tooling to mitigate the downsides of a distributed architecture. Deployment, scalability, coordination & discovery are all well-served problem domains. There remains a few pain points in a services approach I’ve experienced around Service Contracts, and GraphQL has become a great tool in the toolbox for addressing these.
Contract enforcement
Whether a mesh network of point-to-point services or a brokered communications bus, service endpoints should be providing some guarantees about their capabilities. One of the selling points of a service architecture, “right tool for the job”, all but guarantees that services will span technologies. It becomes essential to have strong contracts at the edges to facilitate development and traceability. It is, after all, a service; in’s and outs should be well defined.
Finding well-supported technology-agnostic, cross-platform tooling for describing the capabilities of a service has historically been difficult. The ecosystem around WSDL has friction with recently popular choices for web-friendly stacks. JSON Schema exists, but traction and tooling remain a challenge. Efforts like Swagger and RAML assume much about the transport & application protocols. Further, REST is a broadly misunderstood prescriptive approach, and may not necessarily be appropriate for all use cases.
GraphQL is a strongly-typed, well-specified relative newcomer that hits a good balance. It has great cross-platform tooling support. It plays nice with popular protocols (HTTP), but doesn’t mandate them. It supports bi-directional communications, making it a strong choice for architectures that require pub-sub patterns.
Contract management
Data modeling in a large application is a never-ending stream of changes. Describing the world around us requires coordination of change, particularly in a services architecture. New widgets to model, new properties of those widgets, and the regular grooming out of old paradigms are regular occurrences. In terms of APIs, this is traditionally dealt with by via versioning practices. In RPC systems, different consumers of services can impose different needs on the same service. In practice, this can be a friction point, making it difficult to evolve the capabilities of a service. Alterations to the format of statically defined response imposes coordination requirements that has a chilling effect on change.
GraphQL inverts the typical RPC relationship and offers a CQRS approach. A service advertises a catalog of its capabilities and lets the client specify the structure of the response. This inversion completely eliminates the friction that comes from competing needs of service consumers. New fields can be exposed by the service at will without impacting existing clients. Old fields can be marked as deprecated allowing for transition periods. Managing this kind of slow evolution at the schema layer (as opposed to the operational layer, i.e. services running multiple versions concurrently) simplifies the DevOps model considerably.
GraphQL ships with with a language agnostic schema definition language. Having authored API specs across all the mentioned approaches, I can say without hesitation that it’s the lowest friction DSL I’ve worked with. The cleanliness of the format makes for easy to consume pull requests; it becomes easy to see across teams how the world is changing. Via directives, the specification is extensible, allowing a declarative approach to domains like traits, authentication, & authorization.
Mesh network application topologies can be unwieldy territory for developers to reason about. GraphQL’s strengths position well as a thin routing layer and coordination point. It can expose the full capabilities of your back office, regardless of where the specific data comes from under a single, explorable interface. The tooling is great, the community is vibrant, and solves some real problems seen in the trenches of application development.