DEV Community

Cover image for gRPC no es moda: es el contrato que REST nunca te dio
Juan Torchia
Juan Torchia Subscriber

Posted on Originally published at juanchi.dev

gRPC no es moda: es el contrato que REST nunca te dio

Imaginate esto: tenés quince microservicios hablando entre sí. Cada uno expone su API REST, cada uno tiene su propio JSON con sus propias convenciones de nombres, y cada vez que alguien cambia un campo en el servicio de pagos, tres equipos más se enteran cuando todo explota en producción. Documentás con Swagger, pero el Swagger se desactualiza. Escribís clientes HTTP a mano, o generás algo con OpenAPI que funciona "más o menos". Y cuando necesitás que el servicio A le pregunte algo al servicio B diez mil veces por segundo, el overhead de JSON + HTTP/1.1 empieza a dolerte en la factura de infraestructura.

Ese dolor específico — comunicación inter-servicios con contratos que se rompen en silencio y performance que no escala — es el que gRPC viene a resolver. No es una moda. Google lo diseñó para resolver ese problema puntual dentro de su propia infraestructura, y después lo liberó como proyecto open source. Hoy aparece en tres awesome lists independientes, lo cual en el sistema de curación que vengo laburando en esta serie es señal fuerte: no es ruido, es consenso real de la comunidad.

Si vos venís de laburar con REST toda la vida (como yo laburé un buen tiempo administrando infraestructura antes de meterme de lleno al desarrollo), la primera vez que ves gRPC en acción te cambia la cabeza. No es "otro framework HTTP". Es un paradigma distinto para pensar cómo se hablan tus servicios.

Qué hace

gRPC es un framework de Remote Procedure Calls que corre sobre HTTP/2 y usa Protocol Buffers (protobuf) como mecanismo de serialización por default. En vez de exponer endpoints REST y que cada cliente arme su propio request, definís un contrato — un archivo .proto — y de ahí se genera código cliente y servidor en el lenguaje que necesites: Go, Java, Python, C++, Node. El mismo contrato, múltiples lenguajes, menos espacio para que cada equipo interprete el JSON a su manera.

Mirá cómo se ve un contrato básico:

// pedidos.proto
// Definimos el servicio y los mensajes que va a intercambiar
syntax = "proto3";

package pedidos;

// El servicio expone un método RPC, como si fuera una función remota
service PedidosService {
  rpc ObtenerPedido (PedidoRequest) returns (PedidoResponse);
}

// Los mensajes son como DTOs, pero tipados y versionables
message PedidoRequest {
  string id_pedido = 1;
}

message PedidoResponse {
  string id_pedido = 1;
  double monto_total = 2;
  string estado = 3;
}
Enter fullscreen mode Exit fullscreen mode

De ese archivo, el compilador de protobuf (protoc) genera automáticamente las clases de serialización y los stubs de cliente/servidor. Si vos venís del mundo Java (como yo, que arranqué ahí mi carrera como developer), esto te va a sonar parecido a lo que hacía SOAP con WSDL, pero sin el peso muerto de XML.

Del lado del servidor en Java, la implementación queda así:

// Implementamos el servicio generado automáticamente desde el .proto
public class PedidosServiceImpl extends PedidosServiceGrpc.PedidosServiceImplBase {

    @Override
    public void obtenerPedido(PedidoRequest request, 
                               StreamObserver<PedidoResponse> responseObserver) {
        // Acá iría la lógica real, consultando la base de datos
        PedidoResponse response = PedidoResponse.newBuilder()
            .setIdPedido(request.getIdPedido())
            .setMontoTotal(1500.50)
            .setEstado("CONFIRMADO")
            .build();

        // onNext envía la respuesta, onCompleted cierra el stream
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}
Enter fullscreen mode Exit fullscreen mode

Fijate que no hay JSON por ningún lado. El payload va serializado en binario, lo cual en teoría significa payloads más chicos y parsing más rápido que un JSON equivalente. Y como corre sobre HTTP/2, tenés multiplexación de requests sobre una sola conexión TCP, streaming bidireccional nativo y header compression — las piezas que, en el paper y la documentación oficial de gRPC, explican la ventaja frente a REST + HTTP/1.1 en escenarios de tráfico alto. No tengo benchmarks propios corridos para este post; lo dejo como lo que es, una ventaja de diseño documentada por el proyecto, no una medición mía.

Por qué está en la lista

La señal de consenso — tres awesome lists independientes mencionándolo — no es casualidad. gRPC apunta a un problema que cualquiera que laburó con microservicios a escala conoce: la falta de contratos fuertes entre servicios. Con REST + JSON, el contrato es una convención que vive en la cabeza de los devs y en una documentación que se desactualiza. Con gRPC, el contrato es código generado: si cambiaste un campo y rompiste algo, el compilador te lo marca, no lo descubrís en producción un viernes a las seis de la tarde.

La otra razón es que el code generation elimina el boilerplate de serialización manual — no escribís parsers de JSON a mano, no mantenés DTOs duplicados en cada lenguaje. Eso es valor concreto, independiente de cuánto gane o no en performance tu caso puntual.

Es el tipo de herramienta que no brilla en un demo de cinco minutos, pero que tiene sentido cuando tenés una arquitectura con decenas de servicios hablando entre sí. Ahí es donde el ecosistema JVM (si laburás con Spring Boot, hay soporte vía grpc-spring-boot-starter) se beneficia de este approach frente a mantener quince clientes REST hechos a mano.

Cuándo NO usarlo

Ahora, seamos honestos: gRPC no es gratis, y esto es lo que más me interesa dejar claro. Protobuf y los patrones async/streaming tienen una curva de entrada que no es trivial — si tu equipo nunca laburó con esto, contá con perder tiempo entendiendo por qué el stub generado no hace lo que esperabas en el primer intento. No tengo un número de días para darte porque depende del equipo, pero es una friccion real, no un detalle menor.

El debugging distribuido también es más tedioso: no podés pegarle con curl a un endpoint gRPC como hacías con REST, necesitás herramientas extra como grpcurl o BloomRPC para inspeccionar tráfico.

Tampoco tiene sentido si tu API la vas a consumir directamente desde un browser (necesitás gRPC-Web con un proxy intermedio, otra capa de complejidad) o si estás armando una API pública que terceros van a consumir sin control sobre su stack — ahí REST + OpenAPI sigue siendo más amigable. Si tu sistema son dos o tres servicios con tráfico bajo, probablemente estés agregando complejidad que no necesitás. Para esos casos, quedate con REST o mirá alternativas más livianas como tRPC si estás en un monorepo TypeScript.

Cierre

gRPC tiene sentido cuando tenés el problema específico que resuelve: comunicación inter-servicios a escala, con contratos fuertes y una curva de aprendizaje que estás dispuesto a pagar. No lo adoptaría solo porque aparece en tres awesome lists — esa señal te dice que la comunidad lo validó, no que tu equipo esté listo para el costo de entrada.

Esto es la entrega #13 de Awesome Curated: The Tools, donde voy desmenuzando herramientas que pasaron el filtro de nuestro sistema de curación. Si te interesa el lado de infraestructura y runtimes, capaz te cope también el post sobre Node.js y su event loop, o si andás por el lado de redes, Sniffnet para monitorear tráfico sin volverte loco. La serie completa está en /blog/series/awesome-curated-tools.


Este artículo fue publicado originalmente en juanchi.dev

Top comments (0)