# REST API to GraphQL Migration

## Summary


While GraphQL has its limitations, there are many advantages that make it worthwhile to migrate existing REST APIs to GraphQL. To reap these benefits, it's important to think in terms of graphs rather than endpoints. 

The migration itself can be done in one go for small projects. An incremental approach is preferred for complex projects handled by large teams. For most projects, it's expected that current REST APIs will coexist with new GraphQL APIs. This is because clients may not migrate to new app versions or update their code immediately.

In general, migration will involve building the **GraphQL schema** and writing the **resolvers** for that schema.

## Discussion

### What's a possible migration path from REST to GraphQL?

Let's assume that we're using REST API and React client (a). We can start by keeping the REST endpoints but wrapping it with a **GraphQL gateway** (b). We need to define the GraphQL schema. React client will now call a single GraphQL endpoint. Resolvers will use REST endpoints for fetch the data. 

A natural evolution from here is to implement the **GraphQL server** (c). We can remove the gateway. React client will directly call the new GraphQL API. This has direct access to the database layer and therefore lower latency compared to the gateway architecture. REST endpoints may coexist to support legacy clients.

A React client does imperative data fetching and might do manual client-side caching. By migrating to **Apollo Client**, we can do declarative data fetching and zero-config caching. By using Apollo Link REST, we don't even need changes at the server side. This could be an easy way to get started. The final goal is to have GraphQL API and Apollo Client (d). 


### To design for GraphQL, what sort of mindset should I have?

One study found that reducing the number of API calls by migrating to GraphQL is not a trivial exercise. Suppose the current code is organized to consume small amounts of data returned by specific REST endpoints. Refactoring this into fewer endpoints that return large graph structures requires a graph-based mindset.

Developers have to stop thinking in terms of endpoints and start thinking in terms of graphs. It's important to understand this before designing the GraphQL schema. A typical endpoint-based approach is to ask, "What pages are there and what data each of them needs?" With graph-based approach, we should instead focus on the data and its relationships, and seek to expose these to clients. 

Consider a blogging site. Let's think about exposing user information. Relationships from the user might include posts, comments, liked articles, groups, etc. Thus, we are building a graph around the user. Relationships are bidirectional. When focusing on a comment, we should also link it back to the user. 

In short, 

> Think in graphs, not endpoints. Describe the data, not the view.


### How is TypeScript relevant to GraphQL?

Unlike vanilla JavaScript, TypeScript gives type safety at the client side. GraphQL gives type safety at the server side. 

Suppose we have a client that uses only JavaScript. If this client makes a query to the GraphQL server in which the types don't match. This error will be caught at the server during runtime. Instead, if the client code had been in TypeScript, such a mismatch would have been caught during the build process. We can deploy our code with lot more confidence. 

A good approach is to define GraphQL schema and then use tools to auto-generate TypeScript types for the front-end. Ideally, we could extend this to the database layer so that from browser to the database, types are consistent. 

In general, we should strive for type consistency systemwide. At Airbnb, they defined Thrift IDL that was then compiled into GraphQL schema. Moreover, they then automatically generated TypeScript types from the GraphQL schema. 


### Should I implement caching for my GraphQL service?

A single client query can trigger multiple resolvers. GraphQL resolvers run as independent units. This has the benefit that even if some of them fail, the ones that succeed return the requested data to the client. One problem is that across resolvers there could be many duplicate calls to REST endpoints. 

It's to solve this problem that a caching layer is helpful. Resolvers need not worry about optimizing their calls to REST endpoints. At Airbnb, engineers approached this problem via what they call a *data-centric schema* and a *data hydration layer*. 

At another level, we can cache client request-response. Since GraphQL doesn't support HTTP-level caching, we need an alternative. It's possible to use application-level caching, such as Spring Boot caching. Database queries can also be optimized via caching. 


### Could you share some case studies on migrating to GraphQL?

At Netflix, the Marketing Technology team adopted GraphQL to solve their network bandwidth bottlenecks. Their use cases were complex and building custom REST endpoints for each page was cumbersome. GraphQL matched their graph-oriented data structures. They could roll out features lot faster. A GraphQL middle layer reduced number of direct calls from the browser. Instead, server-to-server calls within the data centre gave 8x performance boost. Payload of 10MB reduced to 200KB. 

At Airbnb, they reconciled legacy presentation services with GraphQL by having Thrift/GraphQL translators per service. These services were then exposed to clients via a GraphQL gateway service. 

At PayPal, a user checkout involved many round trips. Reducing round trips with REST meant overfetching data. They also found that UI developers spent less time building UI. Mostly, they were trying to figure out where and how to fetch data. After moving to GraphQL, data performance and developer productivity improved. 

Interested readers can head to the official GraphQL website that shares a number of GraphQL case studies.


### Are there tools that help with GraphQL migration?

GraphiQL is an in-browser IDE. Via GraphiQL, you can look at the schema, make queries and look at the responses. GraphQL Editor, GraphQL Playground and GraphQL Voyager are other useful tools. 

Apollo Server and Apollo Client provide server and client-side implementations of GraphQL. Apollo Client can integrate with React, Angular or Vue frameworks. As an alternative to Apollo Client, there's Relay to act as a bridge between GraphQL and React. 

There are many tools that can read your REST API files and export GraphQL schema. Apimatic's API Transformer is one such tool. Input files can be in various formats such as OpenAPI, RAML, or API Blueprint. This tool can also migrate SOAP users by translating WSDL files. 

Some clients may want to use only REST. To avoid maintaining two codebases, we can have a GraphQL schema and generate REST APIs from it. Sofa is a Node.js package that does this. 


### How I do map REST features to their equivalent GraphQL features?

Using REST, a client would make an endpoint call, parse the response and make further calls to get all relevant data. This is the N+1 problem. This can be solved using the nested API design but this leads to overfetching. With a well-designed GraphQL API, clients should be able to and should request only relevant data with a single API call. Moreover, we should make use of **connections**. A connection encapsulates the queried node and other *nodes* to which it's connected by *edges*. This comes directly from the underlying graph-based data abstraction. 

In REST, we paginate with a query string such as `?limit=1&page=2`. **Cursor-based pagination** is the GraphQL equivalent. It's typically used with connections using arguments `first`, `last`, `offset` or `after`. 

In REST, POST, PUT or DELETE requests modify data. In GraphQL, clients can instead use **mutations**. We could define mutations to create, update or delete items. 

GraphQL prefers serving a versionless API and avoids breaking changes as the API evolves. Clients only request what they need and understand. In REST, the practice has been to serve different versions.  


### Could you share some tips and best practices for moving to GraphQL?

GraphQL should be a thin layer. Tasks such as authentication, caching or database queries should happen below the GraphQL service layer. By doing this, application will be more resilient to changes in platform or services. Likewise, name your fields in a self-documenting manner. Once clients start using them, it becomes hard to change later. 

Don't force clients to replace all their REST endpoint calls to GraphQL. Instead, allow them to adopt GraphQL incrementally. Shopify documentation shows how responses from REST endpoints can include GraphQL IDs that can be used for subsequent GraphQL queries. 

Resolvers should be thin and fetch data asynchronously. Fetch data at field level and de-duplicate requests using a library such as DataLoader. 

Server logs help in debugging GraphQL calls. To debug within the browser, include logs into the response payload when enabled by a flag. 

With GraphQL, we often fetch partial objects that can't be directly used in methods that need full objects. Use duck typing to get around this. 

## Milestones

Jul  
2015

Facebook open sources GraphQL, which is also released as a draft specification. The development of GraphQL within Facebook can be traced back to 2012. 

Jun  
2019

Brito et al. compare the performance of GraphQL against REST using seven open source clients to call GitHub and arXiv APIs. They also make typical queries noted in recent papers presented at engineering conferences. They find that GraphQL results in 94% less number of fields fetched and 99% less number of bytes. These are median values. However, there's no significant reduction in the number of API calls. 

Oct  
2019

Airbnb engineer Brie Bunge shares Airbnb's migration journey to GraphQL. They adopted an incremental approach, making sure the app is always shippable and regression-free. As pre-requisites, they set up GraphQL in the backend and adopted TypeScript in the frontend. Migration itself had five stages. The approach was to first replace REST with GraphQL. Refactoring and optimizations were done later.