Skip to content

Build gRPC with Go (golang) Server Streaming API

Posted on:April 2, 2023 at 12:00 PM

Build gRPC with Go (golang): Server Streaming API

Previously, we discussed the gRPC Unary API, you can check it at this link. In this article, I’ll cover a gRPC call using Server Streaming response implementing client and server Go applications.

What’s a Server Streaming API?

Step 1: Setup Project

the first step is to install the protoc gen go library as a library that will help you create gRPC, run the command below:

    $ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
    $ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1

After that update the PATH on your computer by running the command below:

    $ export PATH="$PATH:**$(**go env GOPATH**)**/bin"

Step 2: Create Proto File

In the second step, of course, we will create the proto file, then we first define the contents of the request and response, then don’t forget to add the name of the service. You can see in the code below:

syntax = "proto3";

package greet;
option go_package = "greet/greetpb";

// model
message Greeting {
    string first_name = 1;
    string last_name = 2;
}

// request
message GreetManyTimesRequest {
    Greeting greeting = 1;
}

// response
message GreetManyTimesResponse {
    string result = 1;
}

service GreetService{
    // server streaming
    rpc GreetManyTimes(GreetManyTimesRequest) returns (stream GreetManyTimesResponse) {}
}
view rawgreet.proto hosted with ❤ by GitHub

After creating the proton file, we will generate the file into a gRPC file using the command below:

    $ protoc greet/greetpb/greet.proto  go_out=plugins=grpc:.

when we run the command, the gRPC file will automatically be created as shown below:

Step 3: Create Server File

After we create the proton file, the next step is to create a server file which I put in the greet_server/server.go folder, here is the code for the server:


package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"strconv"
	"time"

	"github.com/bangadam/grpc-go/greet/greetpb"
	"google.golang.org/grpc"
)

type server struct{}

func (*server) GreetManyTimes(req *greetpb.GreetManyTimesRequest, stream greetpb.GreetService_GreetManyTimesServer) error {
	fmt.Printf("GreetManyTimes function was invoked with %v\n", req)
	firstName := req.GetGreeting().GetFirstName()
	for i := 0; i < 10; i++ {
		result := "Hello " + firstName + " number " + strconv.Itoa(i)
		res := &greetpb.GreetManyTimesResponse{
			Result: result,
		}
		stream.Send(res)
		log.Printf("Sent: %v", res)

		time.Sleep(1000 * time.Millisecond)
	}

	return nil
}

func main() {
	listener, err := net.Listen("tcp", "0.0.0.0:50051")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	fmt.Print("Server started")
	s := grpc.NewServer()
	greetpb.RegisterGreetServiceServer(s, &server{})

	if err := s.Serve(listener); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

As we saw above there is a main func that serves as the main function to run the gRPC server, in addition, there is a GreetManyTimes func that we define based on the name of the service in the prototype file.

Step 4: Create Client File

After we have created the file server, the next step is that we will create a client file that functions as the client, we will create the file in the greet_client/client.go folder, here are the contents of the code:


package main

import (
	"context"
	"fmt"
	"io"
	"log"

	"github.com/bangadam/grpc-go/greet/greetpb"
	"google.golang.org/grpc"
)

func main() {
	cc, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("could not connect: %v", err)
	}
	defer cc.Close()

	c := greetpb.NewGreetServiceClient(cc)

	doServerStreaming(c)
}

func doServerStreaming(c greetpb.GreetServiceClient) {
	fmt.Println("Starting to do a Server Streaming RPC...")

	req := &greetpb.GreetManyTimesRequest{
		Greeting: &greetpb.Greeting{
			FirstName: "bangadam",
			LastName:  "s",
		},
	}

	resStream, err := c.GreetManyTimes(context.Background(), req)
	if err != nil {
		log.Fatalf("error while calling GreetManyTimes RPC: %v", err)
	}

	for {
		msg, err := resStream.Recv()
		if err == io.EOF {
			// we've reached the end of the stream
			break
		}

		if err != nil {
			log.Fatalf("error while reading stream: %v", err)
		}

		fmt.Printf("Response from GreetManyTimes: %v\n", msg.GetResult())
	}
}

Just like the file server, in this client, we also create a func main which is useful for running as the client-side while func doServerStreaming is useful for calling func GreetManyTimes from the server.

Step 5: Run Server and Client

In the last step, we will try to run the two files, namely the server and client, the results will be like the image below:

Conclusion

We have made one type of API using the gRPC concept, of course, there are many types of API that we haven’t implemented with the gRPC concept, you can see the complete code for this article on my **GitHub account**, that’s all from me, don’t forget to claps and share this article if it’s useful for you.

Thanks For Reading!

Available for a new project! Let’s have a talk : Email: bangadam.dev@gmail.com Linkedin: https://www.linkedin.com/in/bangadam