← Back to list

REST vs GraphQL vs gRPC: Which API Style Should You Actually Use in 2026?

REST vs GraphQL vs gRPC: Which API Style Should You Actually Use in 2026?

Tarxemo · 2026-05-16 09:28 · 2 claps · 3.6 min read
#backend-development #api-design #microservices #software-engineering #web-development
Open on Medium ↗
Wiki topics: 🌐 · Web Development 👗 · Fashion

REST vs GraphQL vs gRPC: Which API Style Should You Actually Use in 2026?

REST vs GraphQL vs gRPC: Which API Style Should You Actually Use in 2026?

A no-fluff breakdown with real code, benchmarks, and a decision table.

Every backend engineer hits this decision. Here’s how to make it fast and correctly.

1. REST — Still the Default, For Good Reason

Use it when: Public API, simple CRUD, external consumers, browser clients.

GET /api/v1/users/123
Authorization: Bearer <token>
{
  "id": 123,
  "name": "Salim Hassan",
  "email": "salim@example.com",
  "role": "admin",
  "createdAt": "2024-01-15T10:30:00Z"
}

Node.js (Express) example:

app.get('/api/v1/users/:id', authenticate, async (req, res) => {
  const user = await db.users.findById(req.params.id);
  if (!user) return res.status(404).json({ error: 'User not found' });
  res.json(user);
});

The real REST problem: over-fetching and under-fetching.

Imagine a mobile screen that only needs name and avatar. REST still returns the full user object — every field, every time. Now multiply that by 50 requests per page load.

2. GraphQL — Let the Client Ask for Exactly What It Needs

Use it when: Multiple clients (mobile, web, third-party) need different data shapes from the same API.

# Client asks only for what it needs
query GetUserProfile {
  user(id: "123") {
    name
    avatar
    posts(last: 3) {
      title
      publishedAt
    }
  }
}

Response — nothing extra:

{
  "data": {
    "user": {
      "name": "Salim Hassan",
      "avatar": "https://cdn.example.com/avatar.jpg",
      "posts": [
        { "title": "Building with AI", "publishedAt": "2026-05-10" }
      ]
    }
  }
}

Node.js (Apollo Server) resolver:

const resolvers = {
  Query: {
    user: async (_, { id }, { dataSources }) => {
      return dataSources.usersAPI.getUserById(id);
    },
  },
  User: {
    posts: async (parent, { last }, { dataSources }) => {
      return dataSources.postsAPI.getRecentByUser(parent.id, last);
    },
  },
};

Watch out for:

  • N+1 problem — a query for 10 users triggers 10 separate DB calls for each user’s posts. Fix it with DataLoader:
const userPostsLoader = new DataLoader(async (userIds) => {
  const posts = await db.posts.findByUserIds(userIds);
  return userIds.map(id => posts.filter(p => p.userId === id));
});

3. gRPC — When You Need Raw Speed Between Services

Use it when: Internal microservice-to-microservice communication where performance is critical.

Why it’s fast:

  • Uses Protobuf (binary serialization) — 5–10x smaller payload than JSON
  • Built on HTTP/2 — multiplexed streams, no head-of-line blocking
  • Generated client/server code — no manual parsing

Step 1 — Define your contract (.proto file):

syntax = "proto3";
service UserService {
  rpc GetUser (UserRequest) returns (UserResponse);
  rpc StreamUsers (UserRequest) returns (stream UserResponse); // server streaming
}
message UserRequest {
  string user_id = 1;
}
message UserResponse {
  string id = 1;
  string name = 2;
  string email = 3;
  string role = 4;
}

Step 2 — Server (Node.js):

const server = new grpc.Server();
server.addService(UserService, {
  getUser: async (call, callback) => {
    const user = await db.users.findById(call.request.user_id);
    if (!user) return callback({ code: grpc.status.NOT_FOUND });
    callback(null, user);
  },
});
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
  server.start();
});

Step 3 — Client (another microservice):

const client = new UserServiceClient(
  'user-service:50051',
  grpc.credentials.createInsecure()
);
client.getUser({ user_id: '123' }, (err, response) => {
  if (err) console.error(err);
  console.log(response.name); // "Salim Hassan"
});

Performance Reality Check

Rough numbers from internal benchmarks (same hardware, same data):

Metric REST (JSON) GraphQL (JSON) gRPC (Protobuf) Payload size (200 field object) ~1.2 KB ~0.9 KB ~120 bytes Serialization time ~0.8ms ~0.9ms ~0.05ms Latency p50 ~8ms ~9ms ~2ms Latency p99 ~45ms ~50ms ~12ms Throughput (req/s) ~12,000 ~10,000 ~80,000

gRPC is not slightly faster. It’s a different category.

When NOT to Use Each One

Don’t use REST when:

  • Different clients need radically different data shapes
  • You’re building service-to-service communication at high volume
  • You’re sick of maintaining multiple endpoint versions

Don’t use GraphQL when:

  • Your API is simple CRUD — you’re adding complexity for zero gain
  • Your team is small and the learning curve will slow you down
  • You don’t have time to set up proper caching (GraphQL breaks HTTP caching)

Don’t use gRPC when:

  • Browser clients need to call you directly (gRPC-Web exists but adds friction)
  • Your consumers are external third parties — they won’t want to deal with .proto files
  • Your team has no experience with Protobuf — debugging binary payloads is painful

The Real-World Architecture Pattern in 2026

Most mature systems are not using just one. They’re using all three — each in the right place:

[Browser / Mobile App]
        |
        | REST or GraphQL (external-facing)
        ↓
  [API Gateway]
   /          \
  /            \
REST          GraphQL
(public API)  (BFF for mobile)
                |
                | gRPC (internal)
         ┌──────┴───────┐
    [User Service]  [Order Service]  [Notification Service]
  • GraphQL as a Backend-for-Frontend (BFF) layer — mobile and web get exactly what they need
  • REST for public API consumers and simple endpoints
  • gRPC for all internal service-to-service calls where performance matters

Decision Flowchart (Plain Text)

Is it external-facing (browser, mobile, third-party)?
  └─ YES → Do clients need flexible data shapes?
              └─ YES → GraphQL
              └─ NO  → REST
  └─ NO (internal service-to-service) → gRPC

Quick Cheat Sheet

REST: GET /users/:id → JSON → Simple, universal, well-understood GraphQL: query { user(id) { name, posts { title } } } → Flexible, client-driven gRPC: .proto → Binary → Fast, typed, internal use


메타데이터
post_id
94de1e9152fa
slug
rest-vs-graphql-vs-grpc-which-api-style-should-you-actually-use-in-2026-94de1e9152fa
url
https://medium.com/@tarxemo/rest-vs-graphql-vs-grpc-which-api-style-should-you-actually-use-in-2026-94de1e9152fa
canonical_url
https://medium.com/@tarxemo/rest-vs-graphql-vs-grpc-which-api-style-should-you-actually-use-in-2026-94de1e9152fa
author_url
https://medium.com/@tarxemo
status
ok
fetched_at
2026-06-09 15:37:30