Unleash Declarative Data Access with GraphQL

GraphQL is redefining the way that developers interact with APIs, putting application clients in control of the data they consume and placing new requirements on platforms hosting these APIs. You can unleash declarative configuration with GraphQL to solve some of your most challenging application networking problems. 

Understanding when to write code and when to let the platform do the work is a critical tradeoff to understand as you scale GraphQL adoption.

We’ll explain how by following the journey of one company from slow services, unhappy front-end developers, over-taxed infrastructure, and unnecessary server deployments, to a reality where they spend less of their money on cloud infrastructure and wasted developer time, revolutionizing their communications stack in the process. 

Setting the scene

In this example, which I share in greater detail in the webinar demo, let’s say you’re working for Wayne Telecom, the largest telecom services provider based in Gotham City. Wayne Telecom requires highly available, low-latency communication with services from both mobile and web clients. Your company is hemorrhaging money. Your mobile user experience is absolutely dreadful. You’re spending way too much money trying to Band-Aid problems. Not to mention that your development and operation teams are both really unhappy.

Unleash Declarative Data Access with GraphQL

With your current page on your billing web application, fetching data currently requires making multiple calls to various microservices and then aggregating the responses and sending them back to the front end. That takes time and provides a slow user experience. 

Declarative Data Access with GraphQL

The Backend for Frontend option

One solution could be to create an additional back-end service that exposes aggregate endpoints – then the mobile app only has to make a single API call to the BFF service, which will then aggregate the responses from the individual back-end services. In addition, we can apply some further optimizations like content delivery, network-level caching, and load balancing to increase the performance of our system. 

The Backend for Frontend option

But this solution isn’t complete for the way apps are built and distributed in multi-tenant organizations like Wayne Telecom. 

Adding GraphQL into the mix

As we’ve established, we’ve yet to arrive at a complete solution. By utilizing GraphQL on the frontend, we can:

  • Have all of our queries return exactly the data we need and nothing more
  • Use a single query to retrieve data that lives in multiple backend resources
  • Get first-class support for a type schema
  • Leverage tools like GraphQL Playground to explore schema, build up queries interactively, and incorporate those queries into application code

Deploying a GraphQL server, so far, is great news for the frontend teams. Yet there are still some challenges that remain on the backend. Complicating matters, Wayne Telecom is a highly regulated company requiring zero trust architecture and secure communication amongst servers. 

Adopting Istio as a service mesh

That’s where we adopt Istio as a service mesh. Doing so will allow us to externalize general platform features like mTLS, rate-limiting, and caching away from the applications themselves and absorb that into our service mesh infrastructure. 

Want to see this full scenario in action? Watch the full webinar here.

After making the changes to adopt GraphQL and Istio as a service mesh, our revised Wayne Telecom infrastructure looks something like this diagram. 

Unleash Declarative Data Access with GraphQL
This diagram shows a single Kubernetes cluster with Istio installed. There’s an ingress gateway where traffic enters the mesh. From there, requests are forwarded to the GraphQL server, which acts as the backend for the frontend. It manages the dispatching of requests to the backend services. It also aggregates responses and returns those to service clients. All of the internal communication within the mesh is now encrypted using mTLS

Common configuration: Proxy and GraphQL server

Common configuration: Proxy and GraphQL server

This diagram represents a common configuration we see with customers who are deploying GraphQL today. Application teams pick up a GraphQL framework and they write some code to resolve multiple upstream data sources into a GraphQL API. They integrate with a number of libraries in that process and they produce an application deployment that’s then managed by a platform team.

The GraphQL server exporting an API requires protection, so the server is fronted with a proxy managed as cloud-native infrastructure, but that also means a separate deployment requiring code changes to modify and evolve behavior, and represents an extra network hop in our data path and additional operational overhead to maintain it. 

We know there’s a more efficient way to support GraphQL in an application architecture to simplify the lives of app dev and platform engineering teams alike, and address platform concerns like authentication and authorization. 

Options like taking the auth-related context from the request and delegating authNZ decisions to the backend services, or taking that same context and instrument identity-aware auth code directly into the GraphQL server, are not ideal. We’ve added a major new moving part in our server side infrastructure – a dedicated GraphQL server that our platform team must be responsible for owning and maintaining.

What if there were a better way?

Let’s begin exploring for a better way by asking ourselves a few questions:

  • What if GraphQL APIs didn’t require dedicated servers?
  • What if you could re-use existing API Gateways to serve GraphQL, so GraphQL would be just another supported type of API much like REST or OpenAPI or SOAP?
  • What if you could use best DevOps practices like declarative configuration in building out those GraphQL APIs?
  • And finally, what if you could leverage existing API contracts to build GraphQL configuration? In other words, what if you could construct those GraphQL APIs without the underlying services even being aware of GraphQL at the gateway level?

 

Solution: Proxy is a GraphQL server

Common configuration: Proxy and GraphQL server

These questions lead us to a simplified architecture that consolidates GraphQL and Application Networking responsibilities into a single component. What we’re proposing is to update our Envoy proxy fleet so that it can function as a GraphQL server.

Benefits include:

  • Eliminating the development and operational expense of maintaining a separate application deployment.
  • Improving performance and even resilience because we’re avoiding an extra failure mode on the data path
  • Achieving compatibility with the rest of your cloud-native infrastructure, like CI/CD and GitOps workflows

By leveraging the existing capabilities Solo.io provides via a GraphQL Envoy filter, there’s no longer a need to integrate with third-party libraries to create resolvers that run inside GraphQL-specific servers.

With simple configuration changes, we can leverage an existing gateway proxy to add policy-driven authentication and authorization, plus services like rate-limiting, response caching, and WAF rules at the edges of your application network. All of these capabilities are driven by declarative policies. This is far superior to solutions where you have to implement your own policies in application code.

Even better, app teams don’t need to go in and enable pre-existing backend services for GraphQL, or use separate third-party tools to generate code that facilitates the conversion of pre-existing services into GraphQL services.

Instead, they can leverage the existing interface specifications that are already in place on the backend services. By putting a sidecar containing this discovery and translation logic next to each service, incoming GraphQL requests are translated into requests that the application understands in its own protocol. 

That converts all our services that we want to include in the graph into GraphQL services just by including them in our Istio service mesh.

New architectural possibilities

Now we have a new deployment architecture with GraphQL, Istio, and the Gloo Platform. This new model opens up new architectural possibilities, enabling more efficient traffic handling and better separation of concerns within our service deployments. 

New architectural possibilities

In this diagram, we have three backend-for-frontend deployments here, for billing, sales, and HR. But these can now be strictly virtual services. From a deployment standpoint, they all live within our Gateway Envoy proxy, just on different request routing paths. The infrastructure is not only more efficient at runtime, but also much cleaner from a design standpoint, and easier to administer. 

Now we can move from imperative code to implement platform concerns to declarative configuration like a GraphQLApi custom resource to specify how our APIs operate, meaning we can: 

  • Replace programmatic GraphQL servers and resolvers with declarative configuration propagated to Envoy by the control plane.
  • Use GraphQL custom directives, such as the @resolve directive, to link resolver configuration with particular fields.
  • Enable this configuration to be discovered by the control plane from your existing service interfaces, essentially “writing” the GraphQL server for you.

We can discover and create GraphQLApi schema on a per-service basis, leveraging the interface contracts that those services already publish – but that’s not required. It’s also possible to build and maintain our own schema if we prefer that approach, or stitch individual schemas together to create a unified supergraph that spans many services across multiple application teams.

This solution allows clients to think just about the data they need from the graph, and not worry about what services need to be called to retrieve that data. The embedded GraphQL proxy filter will handle all of those details for them.

The Gloo GraphQL demonstration in action

To better help you understand how these elements work together. Watch the declarative approach to GraphQL demo below (the demo starts at 23:39).

Putting it all together

Unleash Declarative Data Access with GraphQL

To wrap up, let’s briefly review the benefits that Wayne Telecom (and perhaps YOU) can derive from transforming your application network to using a declarative GraphQL approach:

  1. Increased developer efficiency, particularly in designing and reasoning about the service-to-service request flow.
  2. Fewer moving server parts to manage and thus fewer points of failure for your system.
  3. Reduced request latency because there is no network hop needed between the proxy and your GraphQL server.
  4. Easy-to-track changes to your GraphQL APIs.
  5. Valuable tools like the GraphQL Playground that allow developers to browse schemas and create queries for the data they want.
  6. Simplified resolvers to declaratively define and reason about.

We’ve accomplished quite a bit through our blog post journey. We’ve adopted a modern application networking approach with Istio and GraphQL, we’ve addressed some major performance and scalability issues, plus we’ve adopted best practices that satisfy both our application and platform teams. Have we rid Gotham City of crime yet? Well, maybe not. But at least we’ve freed up Wayne Telecom’s resources to focus on getting rid of the Joker and his minions once and for all.

If you’d like more information on any of the open source or commercial technologies we’ve discussed today, visit our website, or our free training website at academy.solo.io. 

Thank you to Kevin Dorosh and Sai Ekbote for the original Batman-themed presentation they gave at ServiceMeshCon Europe 2022, which inspired the narrative of this webinar.

READ MORE: Announcing Gloo GraphQL Support in Gloo Mesh