What in REST, How in GraphQL

Should you consider GraphQL for your next Application?

Thank you for following along these series of articles. In my previous article, I introduced you to GraphQL and addressed some of the common misconceptions that exist around it. In this article, I’ll talk more about how GraphQL differs from REST, and when you should be using REST over GraphQL and vice-versa. Towards the end of this article, I will also list different approaches that could help you migrate from REST based applications to GraphQL.

Here is a gist of REST vs. GraphQL:

Commonly used REST features, and their implementation in GraphQL

Request lifecycle in REST vs. GraphQL

GraphQL is typed, and lets clients use a single HTTP endpoint to run multiple queries and mutations for fetching and posting data to the backend. This simplifies the workflow of requests that happen between clients and the server. It becomes more evident when you fetch related data over the network.

Consider the N+1 problem from my previous post. Let us visualize how client server interactions happen while fetching the team details using REST endpoints:

Clients make a request to fetch the team details. The response from the server might be in the following shape:

GET api/teams/1

This response consists of 2 players, with individual links to fetch the player responses. Now, the client will make additional 2 requests to the server to fetch the data of each player. The response for each of these requests could look like this:

GET api/teams/1/players/p1

As you can see, if the parent response (team details) consists of N children (players data), the client now has to make N+1 requests to render this team details view, as demonstrated below:

REST — Fetching team details

With GraphQL, you will only make a single query to fetch the necessary information, as shown below:

/graphql — query TeamDetails

The above query is constructed by the client and is sent to the service in a single HTTP request. The GraphQL server will then process this query and generate a response that is identical to the shape of the request. Note that the number of roundtrips made to the Data Source, remains the same. GraphQL allows batching of requests, so in fact, this could lead to fewer number of roundtrips to the Data Sources to resolve related nested fields. I will talk about GraphQL batching in subsequent posts.

GraphQL way of fetching the team details

Grass is “always” greener on the other side!

Or maybe not 🙂. GraphQL simplifies a great deal on the client end, but the burden of work is now transferred to the server side. This is not a bad thing though, if you are deploying and maintaining your application across multiple form factors and platforms. There are some challenges that you need to be aware of, while setting up and maintaining a GraphQL server:

  • You would have to design a GraphQL schema that works for your application and identify the types, their relationships, write resolvers, batch requests to your Data Source (Again, I will go through these concepts in the later posts).
  • You need to figure out the right Authorization strategy for your service. You can set Authorization rules at both schema level and field level, in the response for each query or mutation.
  • REST was introduced and defined about 19 years ago. So, there are plenty of tooling and middle-wares support available for REST based services, in comparison to GraphQL.
  • GraphQL is backed by a specification contrary to REST, which is a set of guidelines, so there is now a support for implementations in multiple programming languages. You can find an exhaustive list of server-side frameworks here. You would need to figure out which of these libraries work for you.

Managed GraphQL services like AWS AppSync mitigate this complexity on the server side as they take over a majority of this workload.

When to use REST?

REST and GraphQL are in fact complementary, and they are used for specific purposes. The following use cases are an overkill for GraphQL but are perfect for REST services:

  • Form based CRUDL endpoints — Let’s say you are building a website for Drivers License application, you don’t need to expose a GraphQL schema for this scenario. This is because, you will end up fetching and updating every field exposed to the user in this form.
  • Another useful use case for REST is server to server communication. For example, a news outlet can expose its data via RESTful API to other news partner, these APIs are meant to be consumed by services and be digested, but not directly displayed on mobile or web platforms, where network bandwidth is usually not the fastest.
  • If there is only going to be one application on a single platform, then REST is useful, given that a lot of developers are experienced in REST and they don’t need to learn an additional technology.

Application Development Lifecycle

When building REST based applications, we work backwards from the customer experience. Different view layouts are designed, and the transitions between these views are identified. A prototype is then built by connecting to a mock data source. This would iterate until a workflow is built with optimal user experience. We then create or consume the REST endpoints accordingly, and plugin the views to fetch the real data. Based on how the app performs, we perform client-side caching and pagination techniques.

In the GraphQL world, the client and the server can be worked upon independently. On the server side, we begin with designing the Schema first by identifying different types that can exist in the application. The relationships between these types are then defined, followed by writing queries/mutations/subscriptions that fits the client needs. This can be worked on in parallel to building the client side views. Once the presentation layer is built with optimal user experience, we then plugin the client to the GraphQL queries/mutations and fetch exactly the data needed for these views.

Migrating REST APIs to GraphQL

As we saw in the previous section, GraphQL enables both client and server to evolve independently, when building new applications. Now I will list out some ways in which you can migrate your existing REST based applications to GraphQL. Before we talk about this, try and ask yourself some of these questions:

  • Why do you want to migrate your REST endpoints to GraphQL?
  • Is the cost measured in terms of time and resources involved in this migration justifiable to your business?
  • Are you currently maintaining multiple versions of REST endpoints?
  • Are there any new mobile applications in your roadmap?

You should also think about the composition of your team — Do you have a dedicated front end team? Are all your engineers full stack? What is the ratio of front end to back end engineers?

You should consider moving to GraphQL if at least one of the following is true in your case:

  • Your current process is tedious, and there is a lot of communication between your frontend and backend teams
  • You are having performance issues with REST endpoints due to over-fetching or under-fetching of data
  • Operational costs on the client is significantly increasing, due to complexity of data or with management of the existing REST endpoints

There are at least 3 approaches you can think of, when transitioning to the GraphQL world:

1. Replacing REST endpoints with GraphQL. Update clients to consume new GraphQL endpoints.

1. Rewriting/Replacing your existing HTTP web server to GraphQL

This approach is helpful if you have some REST endpoints, but don’t have a lot of clients consuming these yet, or if you are planning on revamping both your service and client implementations in one go. This could be a tedious process initially as you setup new GraphQL backend and change client-side implementations, but you will see great benefits once your endpoints are migrated to GraphQL.

One advantage with this approach is that you have a complete implementation of the client-side views and transitions between them. This will help you significantly, in designing a GraphQL schema and defining and implementing queries and mutations.

2. GraphQL as a proxy to your REST endpoints. Clients now consume the GraphQL endpoint.

2. Adding a GraphQL overloaded endpoint that encapsulates your current HTTP endpoints

In this approach, you would spin up new hosts that run the GraphQL engine, and you would then setup new Schemas, define types and relationships. The queries and mutations are then resolved against your existing REST endpoints. This way, the GraphQL endpoint acts as a proxy to your REST endpoints.

This approach is beneficial, if you are creating a new client application and want to use the benefits of GraphQL. All your existing client applications that are not ready to be upgraded to GraphQL, can still continue using your REST endpoints, and you can then update them incrementally.

AWS AppSync, for example, supports resolving GraphQL fields against HTTP Data Sources, so it becomes easier to add a GraphQL proxy for your REST endpoints.
3. Clients consume both REST and GraphQL endpoints.

3. Hybrid approach with both REST and GraphQL endpoints

In this approach, you would only expose newer functionalities over a GraphQL endpoint, and with time, you will deprecate your existing endpoints, so your clients can upgrade to using GraphQL endpoints as needed. This approach can be painful and have bloated client side implementations until you’ve migrated completely to GraphQL. However, this approach does not add any operational costs of transitioning existing REST APIs to GraphQL.

Conclusion

I hope this article gives you an unbiased view of GraphQL and REST, and potentially help you pick the right technology for your next million dollar application. The key takeaway here, is that any feature you‘ve been using inside REST based applications, can be implemented in GraphQL in some form or another. If you are convinced that GraphQL suits your needs and you’d like to learn more about it, I’ll dive deep into the GraphQL concepts, such as Queries, Mutations, Subscriptions, Error handling, Batching and DataLoader in my next couple of articles.