DEV Community

Stack Horizon
Stack Horizon

Posted on

REST vs GraphQL in Practice

The Real Trade-offs

After building APIs with both REST and GraphQL, I've learned that the choice isn't about which is "better" but about what your consumers need. Here's a practical breakdown based on real projects.

REST: Predictable and Simple

REST is still my default for most public APIs. The model is straightforward: resources, HTTP methods, and status codes. Clients know exactly what to expect.

// REST: fetch a user and their posts separately
const user = await fetch('/users/1').then(r => r.json());
const posts = await fetch('/users/1/posts').then(r => r.json());
Enter fullscreen mode Exit fullscreen mode

When REST shines:

  • Simple CRUD apps where resources map well to endpoints
  • Public APIs where you want predictable caching (GET requests are cacheable by default)
  • Teams familiar with HTTP semantics
  • When you don't need nested data often

The pain point: over-fetching and under-fetching. Your /users/1 endpoint returns everything, even if the client only needs a name. And if you need user + posts + comments, you're making multiple round trips.

GraphQL: Precise and Flexible

GraphQL lets clients ask for exactly what they need. One request, one response.

query {
  user(id: 1) {
    name
    posts {
      title
      comments { text }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

When GraphQL shines:

  • Mobile apps with limited bandwidth (one request instead of many)
  • Complex, nested data relationships
  • Multiple client types (web, mobile, third-party) needing different data shapes
  • Rapid iteration where frontend needs change often

The pain point: complexity. You're now managing a schema, resolvers, and a query language. Caching is harder because GET-style caching doesn't work. And you can easily create performance problems with deeply nested queries.

Performance in Practice

I've seen teams assume GraphQL is always faster. It isn't. The classic N+1 problem is real.

// Bad: resolver that queries per post
const resolvers = {
  User: {
    posts: (user) => db.posts.find({ userId: user.id })
  }
}
Enter fullscreen mode Exit fullscreen mode

If a client queries 10 users, that's 10 queries just for posts. You need DataLoader or similar batching:

const DataLoader = require('dataloader');
const postLoader = new DataLoader(ids => db.posts.find({ userId: { $in: ids } }));

const resolvers = {
  User: {
    posts: (user) => postLoader.load(user.id)
  }
}
Enter fullscreen mode Exit fullscreen mode

That's extra code and thinking. REST doesn't have this problem because endpoints are fixed.

Tooling and Ecosystem

REST has mature tooling: OpenAPI specs, Postman collections, and every HTTP client works out of the box. GraphQL has GraphiQL and code generation, but you'll often need to build your own client logic.

For error handling, REST uses status codes (404, 500). GraphQL always returns 200 and puts errors in the response body, which can surprise developers expecting HTTP semantics.

My Rule of Thumb

  • Start with REST unless you have a clear need for GraphQL's flexibility.
  • Choose GraphQL if you have multiple clients with different data needs, or a complex domain with deep relationships.
  • Consider a hybrid: use REST for simple resources and add a GraphQL layer only where it adds value.

Practical Example: Both in One App

I worked on an app where we exposed REST for user management (simple CRUD) and GraphQL for the dashboard (which needed aggregated data from several services). It worked well because each tool did what it's best at.

// REST endpoint for simple actions
app.post('/api/users', createUser);

// GraphQL for complex queries
const server = new ApolloServer({ typeDefs, resolvers });
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

Don't let hype drive your decision. Evaluate your actual use cases. If your API is mostly CRUD and you control the clients, REST keeps things simple. If you have a data-heavy frontend with many views, GraphQL can save you time and bandwidth. Both are valid, and you can use them together.

Remember: the best API is one your team can maintain and your consumers can use without frustration.

Top comments (0)