Saltar al contenido

gRPC vs REST: cuándo usar cada uno

Comparación práctica de gRPC y REST en servicios backend: rendimiento, experiencia de desarrollo, streaming y los compromisos que deciden cuál usar.

4 min de lectura
Diagrama comparativo lado a lado de los patrones de comunicación de gRPC y REST entre servicios

REST es el estilo de API por defecto para servicios web. gRPC es el estándar por defecto para la comunicación de alto rendimiento entre servicios. Pero la elección no siempre es obvia: muchos equipos eligen REST cuando gRPC les ahorraría dolores de cabeza reales de ingeniería, y otros adoptan gRPC cuando REST habría sido perfectamente suficiente.

La respuesta depende de quiénes son tus clientes, qué rendimiento necesitas, si necesitas streaming y cuánto valoras la compatibilidad con el navegador frente a la seguridad de tipos.

La diferencia fundamental

REST usa HTTP/1.1 (o HTTP/2), envía JSON (normalmente) y se apoya en las rutas de la URL y en los verbos HTTP para su semántica. gRPC usa HTTP/2, envía payloads binarios de Protocol Buffers y define servicios y métodos en archivos .proto que generan código tipado de cliente y de servidor.

tstypescript
// REST: JSON over HTTP — human-readable, widely supported
// POST /api/users
// Content-Type: application/json
// { "name": "Alice", "email": "alice@example.com" }
 
// Response: 201 Created
// { "id": "user-123", "name": "Alice", "email": "alice@example.com" }
 
// gRPC: Protocol Buffers over HTTP/2 — binary, type-safe, fast
// Defined in a .proto file:
protobufprotobuf
// user_service.proto
syntax = "proto3";
 
package users;
 
service UserService {
  rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
  rpc GetUser(GetUserRequest) returns (User);
  rpc ListUsers(ListUsersRequest) returns (stream User);  // Server streaming
  rpc UpdateUsers(stream UpdateUserRequest) returns (UpdateUsersResponse); // Client streaming
}
 
message CreateUserRequest {
  string name = 1;
  string email = 2;
}
 
message CreateUserResponse {
  string id = 1;
  string name = 2;
  string email = 3;
}
 
message User {
  string id = 1;
  string name = 2;
  string email = 3;
  int64 created_at = 4;  // Unix timestamp
}
 
message GetUserRequest {
  string id = 1;
}
 
message ListUsersRequest {
  int32 page_size = 1;
  string page_token = 2;
}
 
message UpdateUserRequest {
  string id = 1;
  string name = 2;
  string email = 3;
}
 
message UpdateUsersResponse {
  int32 updated_count = 1;
}

Comparación de rendimiento

La serialización binaria de gRPC y el multiplexado de HTTP/2 le dan una ventaja de rendimiento significativa en la comunicación entre servicios.

tstypescript
// JSON serialization vs Protocol Buffers
 
// A typical user object in JSON: ~150 bytes
const jsonPayload = {
  id: "user-123",
  name: "Alice Johnson",
  email: "alice@example.com",
  createdAt: 1648684800,
  roles: ["admin", "editor"],
};
// JSON.stringify: ~120 bytes
 
// Same data in Protocol Buffers: ~45 bytes
// Binary encoding: field numbers + wire types + values
// No field names transmitted — just indices
// 60-70% smaller on average for typical payloads
 
// Performance implications at scale:
// 10,000 requests/second × 150 bytes (JSON) = 1.5 MB/s network
// 10,000 requests/second × 45 bytes (Protobuf) = 0.45 MB/s network
// 3x less bandwidth, 2-5x faster serialization/deserialization
tstypescript
// ❌ Using REST/JSON for high-throughput internal services
interface InternalServiceCall {
  protocol: 'REST/JSON';
  serialization: '~5ms per large payload';
  networkOverhead: 'HTTP/1.1 head-of-line blocking, text headers';
  typesSafety: 'Manual — OpenAPI spec may drift from implementation';
  // At 50k req/s between services, this adds up significantly
}
 
// ✅ Using gRPC for high-throughput internal services
interface OptimizedServiceCall {
  protocol: 'gRPC/Protobuf';
  serialization: '~0.5ms per large payload';
  networkOverhead: 'HTTP/2 multiplexing, binary headers';
  typeSafety: 'Generated code — proto file IS the implementation contract';
  // 10x serialization improvement, multiplexed connections
}

Streaming: donde gRPC brilla

gRPC soporta de forma nativa cuatro patrones de comunicación. REST soporta petición-respuesta. Todo lo demás requiere soluciones alternativas como WebSockets, Server-Sent Events o long polling.

tstypescript
// gRPC streaming patterns
 
// 1. Unary — standard request/response (like REST)
// Client sends one message, server sends one response
async function getUser(id: string): Promise<User> {
  return client.getUser({ id });
}
 
// 2. Server streaming — server sends a stream of responses
// Client sends one request, server sends many responses
async function* listUsers(pageSize: number): AsyncGenerator<User> {
  const stream = client.listUsers({ pageSize, pageToken: '' });
  for await (const user of stream) {
    yield user;
  }
}
 
// 3. Client streaming — client sends a stream of requests
// Client sends many messages, server sends one response
async function batchUpdateUsers(
  updates: AsyncIterable<UpdateUserRequest>
): Promise<UpdateUsersResponse> {
  return client.updateUsers(updates);
}
 
// 4. Bidirectional streaming — both sides stream simultaneously
// Client and server send messages independently
async function syncUsers(
  localChanges: AsyncIterable<UserChange>,
  onRemoteChange: (change: UserChange) => void
): Promise<void> {
  const stream = client.syncUsers();
 
  // Send local changes
  for await (const change of localChanges) {
    stream.write(change);
  }
 
  // Receive remote changes
  stream.on('data', onRemoteChange);
}

Compromisos en la experiencia de desarrollo

tstypescript
// REST developer experience
 
// Pros:
// - cURL-friendly: curl http://localhost:3000/api/users/123
// - Browser-testable: just open the URL
// - Massive ecosystem: Express, Fastify, every HTTP library
// - Human-readable payloads: JSON is text
// - Low barrier to entry: everyone knows HTTP + JSON
 
// Cons:
// - No generated types: you write clients manually
// - Schema drift: OpenAPI spec and code get out of sync
// - Verbose: HTTP headers, JSON keys repeated in every message
// - No native streaming: need WebSockets or SSE for real-time
 
// gRPC developer experience
 
// Pros:
// - Generated clients: proto file → TypeScript/Go/Python/etc.
// - Type safety: compiler catches mismatches between services
// - Built-in streaming: first-class support for all 4 patterns
// - Performance: binary serialization, HTTP/2 multiplexing
 
// Cons:
// - Not browser-native: need gRPC-Web proxy or Connect
// - Harder to debug: binary payloads aren't human-readable
// - Tooling complexity: protoc compiler, code generation pipeline
// - Smaller ecosystem: fewer middleware options than REST
tstypescript
// REST: easy to debug with standard tools
// $ curl -s http://localhost:3000/api/users/123 | jq
// {
//   "id": "user-123",
//   "name": "Alice",
//   "email": "alice@example.com"
// }
 
// gRPC: need specialized tools
// $ grpcurl -plaintext localhost:50051 users.UserService/GetUser
// Requires grpcurl, grpc_cli, or Postman gRPC support
// Binary payload must be decoded to be readable

Marco de decisión

tstypescript
// When to choose REST
const chooseREST = {
  publicAPI: true,               // Clients are external developers
  browserClients: true,          // Frontend applications consume the API
  simpleCRUD: true,              // Standard create/read/update/delete
  teamFamiliarity: 'REST',      // Team knows REST, not gRPC
  debuggability: 'important',    // Need to curl and inspect easily
  ecosystem: 'broad',           // Need extensive middleware options
};
 
// When to choose gRPC
const chooseGRPC = {
  serviceToService: true,        // Internal communication between services
  highThroughput: true,          // 10k+ requests/second between services
  streaming: true,               // Real-time data feeds, event streams
  polyglot: true,                // Services in different languages need type safety
  latencySensitive: true,        // Every millisecond matters
  strictContracts: true,         // Schema-first development with enforcement
};
 
// The hybrid approach: REST for external, gRPC for internal
const hybridArchitecture = {
  externalAPI: 'REST/JSON',      // Public-facing, browser-friendly
  apiGateway: 'translates',      // Converts REST ↔ gRPC at the boundary
  internalServices: 'gRPC',      // Type-safe, high-performance
  // Best of both worlds — but adds gateway complexity
};

Puntos clave

  1. REST para APIs externas, gRPC para servicios internos — el patrón más común y práctico en las arquitecturas modernas
  2. La seguridad de tipos de gRPC evita el desfase de esquemas — el archivo .proto es a la vez la documentación y la fuente de la generación de código
  3. La serialización binaria importa a escala — los Protocol Buffers son de 3 a 10 veces más pequeños y de 2 a 5 veces más rápidos de serializar que JSON
  4. El streaming es la funcionalidad estrella de gRPC — el streaming de servidor, de cliente y bidireccional son ciudadanos de primera clase
  5. REST es más fácil de depurar y de adoptar — cURL, las DevTools del navegador y la familiaridad universal hacen que REST tenga menos fricción para la mayoría de equipos
  6. Considera un enfoque híbrido — una pasarela REST para los clientes externos y gRPC entre los servicios internos ofrece el mejor equilibrio
Wilfredo Rujel

Wilfredo Rujel

Ingeniero de Software Full Stack

Compartir esta publicaciónX