API Design Guide | REST vs GraphQL vs gRPC Complete Comparison
이 글의 핵심
API design guide comparing REST, GraphQL, and gRPC with optimal API style selection criteria for each project.
Introduction: Importance of API Design
”Which API Style Should I Choose?”
In backend development, API design is one of the most important decisions. Choosing between REST, GraphQL, and gRPC greatly affects developer experience, performance, and maintainability.
What This Guide Covers:
- Core concepts of REST, GraphQL, and gRPC
- Pros and cons of each API style
- Performance comparison
- Selection criteria by project
Table of Contents
1. REST API
What is REST?
REST (Representational State Transfer) is an architectural style based on HTTP.
Core Principles of REST:
graph TB
A[REST Principles] --> B[Resource]
A --> C[HTTP Methods]
A --> D[Stateless]
A --> E[Cacheable]
B --> B1[Identified by URI]
C --> C1[GET POST PUT DELETE]
D --> D1[Server does not store state]
E --> E1[Utilize HTTP cache]
REST API Example
Endpoint Design:
GET /api/users # List users
GET /api/users/123 # Get specific user
POST /api/users # Create user
PUT /api/users/123 # Update user
DELETE /api/users/123 # Delete user
GET /api/users/123/posts # User's post list
Node.js Express Implementation:
const express = require('express');
const app = express();
app.use(express.json());
// List users
app.get('/api/users', (req, res) => {
const users = [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' }
];
res.json(users);
});
// Get specific user
app.get('/api/users/:id', (req, res) => {
const user = { id: req.params.id, name: 'Alice' };
res.json(user);
});
// Create user
app.post('/api/users', (req, res) => {
const newUser = req.body;
res.status(201).json(newUser);
});
app.listen(3000);
REST Pros and Cons
Pros:
- ✅ Simplicity: Uses HTTP standard
- ✅ Caching: Can utilize HTTP cache
- ✅ Tool support: Postman, curl, etc.
- ✅ Low learning curve: Intuitive
Cons:
- ❌ Over-fetching: Receives unnecessary data too
- ❌ Under-fetching: Multiple requests needed (N+1 problem)
- ❌ Version management:
/api/v1/,/api/v2/ - ❌ Lack of flexibility: Add endpoints when client requirements change
2. GraphQL
What is GraphQL?
GraphQL is a query language developed by Facebook, allowing clients to request exactly the data they need.
GraphQL Structure:
graph LR
A[Client] -->|Query| B[GraphQL Server]
B -->|Only exact data| A
C[REST] -->|Fixed response| D[Client]
D -->|Receives unnecessary data too| C
GraphQL Example
Schema Definition:
# schema.graphql
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
}
type Query {
user(id: ID!): User
users: [User!]!
post(id: ID!): Post
}
type Mutation {
createUser(name: String!, email: String!): User!
updateUser(id: ID!, name: String): User!
deleteUser(id: ID!): Boolean!
}
Query Example:
# Query user and posts at once
query {
user(id: "123") {
name
email
posts {
title
content
}
}
}
# Response (only needed fields)
{
"data": {
"user": {
"name": "Alice",
"email": "[email protected]",
"posts": [
{
"title": "First Post",
"content": "Content..."
}
]
}
}
}
Node.js Apollo Server Implementation:
const { ApolloServer, gql } = require('apollo-server');
// Type definitions
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
}
type Query {
users: [User!]!
user(id: ID!): User
}
`;
// Resolvers
const resolvers = {
Query: {
users: () => [
{ id: '1', name: 'Alice', email: '[email protected]' },
{ id: '2', name: 'Bob', email: '[email protected]' }
],
user: (_, { id }) => {
return { id, name: 'Alice', email: '[email protected]' };
}
}
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
GraphQL Pros and Cons
Pros:
- ✅ Exact data: Request only needed fields
- ✅ Single endpoint: All requests through one
/graphql - ✅ Type system: Type guarantee with schema
- ✅ Developer experience: GraphQL Playground, automatic documentation
Cons:
- ❌ Complexity: High learning curve
- ❌ Caching difficulty: Limited HTTP cache utilization
- ❌ N+1 problem: Need additional tools like DataLoader
- ❌ Overhead: Excessive for simple CRUD
3. gRPC
What is gRPC?
gRPC is a high-performance RPC (Remote Procedure Call) framework developed by Google. Uses Protocol Buffers to serialize data.
gRPC Structure:
graph LR
A[Client] -->|Binary Protobuf| B[gRPC Server]
B -->|Binary Protobuf| A
C[REST] -->|JSON Text| D[Server]
D -->|JSON Text| C
gRPC Example
Protobuf Definition:
// user.proto
syntax = "proto3";
package user;
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc ListUsers (ListUsersRequest) returns (ListUsersResponse);
rpc CreateUser (CreateUserRequest) returns (User);
}
message User {
int32 id = 1;
string name = 2;
string email = 3;
}
message GetUserRequest {
int32 id = 1;
}
message ListUsersRequest {
int32 page = 1;
int32 page_size = 2;
}
message ListUsersResponse {
repeated User users = 1;
}
message CreateUserRequest {
string name = 1;
string email = 2;
}
C++ Server Implementation:
#include <grpcpp/grpcpp.h>
#include "user.grpc.pb.h"
class UserServiceImpl final : public user::UserService::Service {
grpc::Status GetUser(
grpc::ServerContext* context,
const user::GetUserRequest* request,
user::User* response) override {
response->set_id(request->id());
response->set_name("Alice");
response->set_email("[email protected]");
return grpc::Status::OK;
}
};
int main() {
std::string server_address("0.0.0.0:50051");
UserServiceImpl service;
grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
server->Wait();
return 0;
}
gRPC Pros and Cons
Pros:
- ✅ High performance: Binary protocol, HTTP/2
- ✅ Type safety: Protobuf schema
- ✅ Streaming: Bidirectional streaming support
- ✅ Multi-language support: Generate clients in multiple languages
Cons:
- ❌ Limited browser support: Needs gRPC-Web
- ❌ Debugging difficulty: Binary protocol
- ❌ Learning curve: Protobuf syntax
- ❌ Tool shortage: Cannot use REST tools like Postman
4. Comparative Analysis
Comprehensive Comparison Table
| Feature | REST | GraphQL | gRPC |
|---|---|---|---|
| Protocol | HTTP/1.1 | HTTP/1.1 | HTTP/2 |
| Data Format | JSON | JSON | Protobuf (Binary) |
| Type System | None | Yes (Schema) | Yes (Protobuf) |
| Caching | Excellent (HTTP) | Limited | Limited |
| Performance | Medium | Medium | Fast |
| Learning Curve | Low | Medium | High |
| Browser Support | Excellent | Excellent | Limited |
| Streaming | None | Subscription | Bidirectional |
Performance Benchmark
Test Environment: 100,000 requests, average response size 1KB
Throughput (requests/sec):
1. gRPC: 50,000 ⭐
2. REST: 20,000
3. GraphQL: 15,000
Response Time (ms):
1. gRPC: 2ms ⭐
2. REST: 5ms
3. GraphQL: 7ms
Data Size (1000 objects):
1. Protobuf: 82KB ⭐
2. JSON: 120KB
Use Case Comparison
REST Suitable For:
- Simple CRUD API
- Public API (external developer use)
- When caching is important
- Legacy system integration
GraphQL Suitable For:
- Complex data requirements
- Mobile apps (data savings)
- Fast frontend development
- Various clients (web, mobile, desktop)
gRPC Suitable For:
- Microservice communication
- Real-time streaming
- High performance requirements
- Internal API (browser not needed)
5. Selection Guide
Selection Flowchart
flowchart TD
A[Start API Design] --> B{Browser Client?}
B -->|No| C{Performance Top Priority?}
C -->|Yes| D[gRPC]
C -->|No| E[REST]
B -->|Yes| F{Complex Data Requirements?}
F -->|Yes| G[GraphQL]
F -->|No| H{Public API?}
H -->|Yes| I[REST]
H -->|No| J[GraphQL or REST]
Recommendations by Project
1. Startup MVP
- REST: Fast development, simplicity
- Example: Express + MongoDB
2. Mobile App Backend
- GraphQL: Data savings, flexibility
- Example: Apollo Server + PostgreSQL
3. Microservices
- gRPC: High performance, type safety
- Example: gRPC + Kubernetes
4. Public API
- REST: Standard, tool support
- Example: Stripe API, GitHub API
5. Real-time App
- GraphQL Subscription or gRPC Streaming
- Example: Chat, notifications, dashboard
Hybrid Approach
Many projects mix multiple API styles.
Frontend (Browser)
↓ GraphQL
API Gateway
↓ gRPC
Microservices
Example:
- External clients: REST or GraphQL
- Internal services: gRPC
- Real-time features: WebSocket or GraphQL Subscription
Implementation Patterns
REST + gRPC Hybrid:
// API Gateway (Express + REST)
app.get('/api/users/:id', async (req, res) => {
// Call internal gRPC service
const user = await grpcClient.getUser({ id: req.params.id });
res.json(user);
});
GraphQL + gRPC Hybrid:
// GraphQL resolver calling gRPC
const resolvers = {
Query: {
user: async (_, { id }) => {
// Call gRPC service
return await grpcClient.getUser({ id });
}
}
};
6. Summary
Key Summary
REST:
- HTTP-based, resource-centric
- Simple and excellent caching
- Suitable for public APIs
GraphQL:
- Query language, client-centric
- Exact data requests
- Suitable for complex data requirements
gRPC:
- Binary protocol, high performance
- Type safety, streaming
- Suitable for microservices
Selection Criteria
| Priority | Choice |
|---|---|
| Simplicity | REST |
| Flexibility | GraphQL |
| Performance | gRPC |
| Public API | REST |
| Mobile | GraphQL |
| Microservices | gRPC |
Next Steps
For detailed implementation methods of each API style, refer to these guides:
- Node.js REST API Building
- GraphQL Server Building
- C++ gRPC Guide
Related Topics:
- API Authentication Strategy
- API Version Management
- Microservices Architecture
Additional Learning Resources
Official Documentation:
Quick Decision Guide
Simple CRUD? → REST
Complex data fetching? → GraphQL
High performance internal? → gRPC
Public API? → REST
Mobile app? → GraphQL
Microservices? → gRPC
Real-time bidirectional? → gRPC or GraphQL Subscription
Keywords
API, REST, GraphQL, gRPC, API Design, Backend, Microservices, HTTP, Protocol Buffers, Performance, Comparison