The Battle for Transport
REST has been the reigning champion of web APIs for two decades, but GraphQL is challenging that dominance. The choice often comes down to one question: Who controls the data shape?
Over-fetching vs Under-fetching
In REST, the server defines the response. If you hit GET /users/1, you might get 50 fields, even if the mobile app only needs the avatar_url. This is Over-fetching (wasted bandwidth). Conversely, to show a dashboard, you might need to hit /users, /orders, and /notifications. This is Under-fetching (wasted RTT).
GraphQL solves this by allowing the client to ask for exactly what it needs: { user { name, avatar_url, orders { total } } }. This shifts the complexity from the network to the server's resolver logic.
The Caching Dilemma
REST is cacheable at the HTTP level (CDNs, Browser Cache, Proxy). If you GET /articles/1, Cloudflare can serve that for you. GraphQL, usually served via a single POST endpoint, is a black box to CDNs. You have to implement application-level caching (like Normalized Caches in Apollo Client) which is significantly more complex.
Conclusion
Use GraphQL if you have a complex 'Graph' of data and multiple clients (Web, iOS, Android) with different data needs. Use REST if you have simple resources and want to leverage the existing HTTP infrastructure (Caching, Status Codes).