Episode 47 guides migrating from REST to GraphQL: assessment and planning, incremental strategies with the strangler fig pattern, GraphQL wrappers for REST with RESTDataSource, client migration with backward compatibility, and post-migration monitoring and evaluation.

Most teams adopting GraphQL don't start from zero — they have a working REST system. Episode 47 discusses migrating from REST to GraphQL with a safe, gradual strategy that doesn't stop the service.
We'll plan the migration, apply the strangler fig pattern, build a GraphQL wrapper for REST, migrate clients, and evaluate the results afterwards.
Migration starts with mapping, not code. Build a complete inventory:
/users -> query user(id)
/users/:id/posts -> query user(id) { posts }
/posts -> query posts(first, after)
POST /posts -> mutation createPostFrom here set priorities: choose the use cases that benefit most from GraphQL (high over-fetching, N+1 requests) to migrate first, as proof of success (quick wins).
Set a realistic timeline (weekly, not "all at once"), identify risks (unchangeable clients, neglected legacy services), and define measurable success criteria: latency drops by a certain percent, fewer requests per view, and no functional regressions.
The strangler fig pattern shifts the legacy system bit by bit: the new system "wraps around" the old one until it eventually replaces it. For GraphQL:
Run both simultaneously — this removes the "all or nothing" pressure. Use feature flags to route some clients to GraphQL, then expand the scope gradually. Every small release can be rolled back without stopping the service.
When a REST API can't be changed, wrap it with GraphQL. RESTDataSource (episode 8) is the main bridge:
import { RESTDataSource } from "@apollo/datasource-rest";
export class UsersAPI extends RESTDataSource {
baseURL = "https://legacy-api.example.com/";
async getUser(id) {
return this.get(`/users/${id}`);
}
async getPosts(userId) {
return this.get(`/users/${userId}/posts`);
}
}First inspect the REST response shape, for example with curl https://legacy-api.example.com/users/1. Map REST responses to GraphQL shapes in the data source or resolver, and translate REST errors into GraphQL errors (episode 11). Also pay attention to caching: legacy REST APIs may already have cache headers — leverage them in the data source.
Client migration happens gradually:
const useGraphQL = featureFlags.get("graphql-profile");
if (useGraphQL) {
return useGetUserQuery({ variables: { id } });
}
return useLegacyRestUser(id);Prepare rollback at two levels: a feature flag to turn off GraphQL at any time, and a deployable version you can return to. Communicate the migration schedule to internal users — API changes rarely cause technical problems; they often cause communication problems.
After clients move:
Compare against the success criteria: measure round-trip reductions, latency, and development ease. Write down lessons learned (episode 49) and update the documentation — the new GraphQL schema is now the team's main contract.
Key takeaways:
In the next episode, episode 48, you'll learn about GraphQL in various languages — Graphene and Strawberry for Python, GraphQL Java and Spring Boot, gqlgen for Go, GraphQL Ruby for Rails, Lighthouse for Laravel, Hot Chocolate for .NET, and Juniper for Rust. GraphQL isn't just for JavaScript!