Implementando un cliente gRPC en Go

Resumen

Crear un cliente gRPC en Go te permite conectarte a un servidor y ejecutar sus métodos como si vivieran dentro de tu propio código. Aquí aprenderás a implementar un cliente unario y un cliente streaming en Go, replicando el comportamiento que antes probabas con Postman, ideal si ya tienes un servidor gRPC corriendo y necesitas consumirlo desde otra aplicación.

¿Cómo conectar un cliente Go con un servidor gRPC?

Lo primero es abrir el canal de comunicación con el servidor. Para eso creas una carpeta client y dentro un archivo main.go con el paquete main y su función principal.

Dentro de main usas grpc.Dial apuntando a localhost:5070, que es el puerto donde corre el servidor de pruebas. Como segundo parámetro envías grpc.WithTransportCredentials(insecure.NewCredentials()), porque el servidor no tiene SSL instalado [02:10].

¿Qué hace grpc.Dial en Go? Establece una conexión con un servidor gRPC. Recibe la dirección del servidor y opciones de transporte, como credenciales seguras o inseguras según si el servidor usa SSL.

Después validas que no haya error con un log.Fatalf y agregas un defer cc.Close() para que la conexión se cierre cuando termine main. Por último, instancias el cliente con testpb.NewTestServiceClient(cc), pasando la conexión que acabas de crear.

¿Qué pasa si el servidor sí tiene SSL?

En ese caso modificas el segundo parámetro de Dial y cargas las llaves correspondientes en lugar de usar insecure.NewCredentials. La estructura del cliente se mantiene igual.

¿Cómo se implementa un cliente unario en gRPC con Go?

La función doUnary recibe como parámetro un testpb.TestServiceClient y construye la petición que viajará al servidor. Aquí ves en acción la magia de RPC: invocas un método remoto como si fuera local.

Dentro de la función creas un testpb.GetTestRequest con el ID T1, que coincide con el método GetTest definido en el archivo proto. Luego llamas a c.GetTest(context.Background(), req) y recibes la respuesta junto con un posible error [05:30].

Lo interesante de esa línea es que parece una invocación normal a una función dentro del cliente, pero internamente está ejecutando código del servidor en otra subrutina. Esa es la esencia de Remote Procedure Call: abstraer la red para que escribas código casi idéntico al de una función local.

Validas el error y, si todo sale bien, imprimes el struct completo con Printf. La respuesta es de tipo Test, también definido en el archivo proto.

¿Cómo ejecutar el cliente y el servidor a la vez?

Primero corres el servidor con go run server/main.go y luego, en una terminal nueva, ejecutas go run client/main.go. La salida muestra el ID T1 y el nombre del test Golang 101, confirmando que la comunicación funcionó.

¿Cómo enviar streaming desde el cliente al servidor?

Cuando necesitas mandar varios mensajes seguidos al servidor, usas client streaming. La función doClientStreaming recibe el mismo testpb.TestServiceClient y prueba el método SetQuestions, que espera un stream de Question y devuelve un SetQuestionResponse.

Dentro defines una lista de testpb.Question con tres elementos. Cada pregunta tiene su id, answer, question y testId:

  • Q8T1 con respuesta azul y pregunta sobre el color asociado a Golang.
  • Q9T1 con respuesta Google y pregunta sobre la empresa que desarrolló Golang.
  • Q10T1 con respuesta backend y pregunta sobre el uso típico de Golang.

¿Qué es client streaming en gRPC? Es un patrón donde el cliente envía múltiples mensajes al servidor por un mismo stream y, al cerrarlo, recibe una única respuesta consolidada.

Luego invocas c.SetQuestions(context.Background()), que te devuelve el stream que usarás para enviar data [09:15]. Validas el error y recorres las preguntas con range, llamando a stream.Send(question) por cada una.

Dentro del loop agregas un time.Sleep de dos segundos y un log.Println con el ID de la pregunta enviada, para visualizar el intercambio en la terminal.

¿Cómo cerrar el stream y recibir la respuesta final?

Al terminar el loop, llamas a stream.CloseAndRecv(). Con eso le indicas al servidor que ya enviaste toda la data y esperas su respuesta consolidada, que en este caso es un SetQuestionResponse con un mensaje [11:40].

Validas el error con log.Fatalf y, si todo sale bien, imprimes el mensaje del servidor con Printf. Al ejecutar go run client/main.go ves cómo se envían las tres preguntas una tras otra y, al final, el servidor responde con un OK confirmando que recibió el lote completo.

Por qué importa entender RPC al escribir un cliente

Lo que acabas de implementar muestra cómo un RPC se ve a nivel de código real. Llamas a GetTest o SetQuestions como si fueran funciones locales, pero detrás se ejecuta una subrutina en el servidor que devuelve la respuesta definida en el archivo proto.

Esa abstracción es la que hace tan poderoso a gRPC: el contrato vive en el .proto, el servidor implementa la lógica y el cliente la consume sin preocuparse por serialización ni transporte. Ya cubriste el método unario y el client streaming, faltan el server streaming y el bidireccional.

¿Has probado conectar este cliente Go con un servidor gRPC en otro lenguaje? Cuéntame en los comentarios cómo te fue.