At Agira, Technology Simplified, Innovation Delivered, and Empowering Business is what we are passionate about. We always strive to build solutions that boost your productivity.

,

Building High Performance APIs In Go Using gRPC

  • By Reddy Sai
  • September 25, 2017
  • 1548 Views

As web developers we all the know the importance of APIs in web applications, they are considered as the cornerstones of the applications. APIs directs or defines how one application can talk to another application. As the technology advances, the current applications we build will definitely need a High-performance APIs. So here in this article, I’m going to explain how we can build a high-performance APIs in GO using gRPC and protocol buffers. Before going to the actual procedure lets understand gRPC and protocol buffers.

What is gRPC?

RPC stands for remote procedure call. gRPC is an RPC framework that runs anywhere. It allows the transparent communication between client and server applications.

What are protocol buffers?

Protocol buffers are flexible, efficient, and automated. they serializes structured data – think XML, they are very simple yet fast. After defining our data, by using its compiler called protoc we can generate source code in any programming language.

Before you begin,

Install gRPC

Use the following command to install gRPC.

$ go get google.golang.org/grpc

 

Install Protocol Buffers v3

Install the protoc compiler that is used to generate gRPC service code. The simplest way to do this

$ curl -OL https://github.com/google/protobuf/releases/download/v3.0.0-beta-2/protoc-3.0.0-beta-2-linux-x86_64.zip
$ unzip protoc-3.0.0-beta-2-linux-x86_64.zip -d protoc3
$ sudo mv protoc3/protoc /bin/protoc

 

Next, Install the protoc plugin for Go

$ go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

 

Building a sample API in Go:

With the use of gRPC and protocol buffers, here we are going to build an API for example. we use the following directory structure in this application.

grpc
├── client
   └── main.go
├── person
   └── person.proto
   └── person.pb.go
└── server
   └── main.go

 

Message Types and Service Definition :

Here is the source of person.proto file in person directory. This file is protocol buffer file.

syntax = "proto3";
package person;
// The Person service definition.
service Person {   
 // Get all Persons with filter - A server-to-client streaming RPC.
 rpc GetPersons(PersonFilter) returns (stream PersonRequest) {}
 // Create a new Person - A simple RPC
 rpc CreatePerson (PersonRequest) returns (PersonResponse) {}
}
// Request message for creating a new person
message PersonRequest {
 int32 id = 1;  // Unique ID number for a Person.
 string name = 2;
 string email = 3;
 string phone= 4;
 
 message Address {
   string street = 1;
   string city = 2;
   string state = 3;
   string zip = 4;
   bool isShippingAddress = 5;
 }
 repeated Address addresses = 5;
}
message PersonResponse {
 int32 id = 1;
 bool success = 2;
}
message PersonFilter {    
 string keyword = 1;
}

 

We declare the name “person”. When you generate Go source code from proto file, it will add Go package name as “person”.

Generating Go Code for Client and Server:

After defining proto file, we have to generate source code for the gRPC client and server interfaces. We use protoc with gRPC Go plugin for code generation. Now run this protoc from the root directory of the application.

protoc -I person/ person/person.proto --go_out=plugins=grpc:person

 

Now person.pb.go file will be generated in person directory. This gives the code in order to create the server and make client calls.

Creating the gRPC Server:

package main
import (
 "fmt"
 "net"
 "strings"
 "google.golang.org/grpc"
 "golang.org/x/net/context"
 prsn "github.com/agiratech/golang-rpc/person"
)
const (
 port = ":3333"
)
// Person is used to implement prsn.PersonServer.
type Person struct {
 savedPersons []*prsn.PersonRequest
}
// CreatePerson creates a new Person
func (p *Person) CreatePerson(c context.Context, input *prsn.PersonRequest) (*prsn.PersonResponse, error) {
 p.savedPersons = append(p.savedPersons, input)
 return &prsn.PersonResponse{Id: input.Id, Success: true}, nil
}
// GetPersons returns all persons using filter
func (p *Person) GetPersons(fltr *prsn.PersonFilter, stream prsn.Person_GetPersonsServer) error {
 for _, person := range p.savedPersons {
   if fltr.Keyword != "" {
     if !strings.Contains(person.Name, fltr.Keyword) {
       continue
     }
   }
   err := stream.Send(person)
   if err != nil {
     return err
   }
 }
 return nil
}
func main() {
 lis, err := net.Listen("tcp", port)
 if err != nil {
   fmt.Println("failed to listen: ", err)
   return
 }
 // Creates a new gRPC Person
 s := grpc.NewServer()
 prsn.RegisterPersonServer(s, &Person{})
 s.Serve(lis)
}

 

Creating the gRPC Client:

Now lets create gRPC Client using following code.

package main
import (
 "io"
 "fmt"
 "google.golang.org/grpc"
 "golang.org/x/net/context"
 prsn "github.com/agiratech/golang-rpc/person"
)
const (
 address = "localhost:3333"
)
// createPerson calls the RPC method CreatePerson of PersonServer
func createPerson(client prsn.PersonClient, person *prsn.PersonRequest) {
 resp, err := client.CreatePerson(context.Background(), person)
 if err != nil {
   fmt.Println("Could not create Person: ", err)
   return
 }
 if resp.Success {
   fmt.Println("A new Person has been added with id: ", resp.Id)
 }
}
// getPersons calls the RPC method GetPersons of PersonServer
func getPersons(client prsn.PersonClient, filter *prsn.PersonFilter) {
 // calling the streaming API
 stream, err := client.GetPersons(context.Background(), filter)
 if err != nil {
   fmt.Println("Error on get persons: ", err)
   return
 }
 for {
   person, err := stream.Recv()
   if err == io.EOF {
     break
   }
   if err != nil {
     fmt.Printf("%v.GetPersons(_) = _, %v", client, err)
   }
   fmt.Println("Person: ", person)
 }
}
func main() {
 // Set up a connection to the gRPC server.
 conn, err := grpc.Dial(address, grpc.WithInsecure())
 if err != nil {
   fmt.Println("did not connect: ", err)
   return
 }
 defer conn.Close()
 // Creates a new PersonClient
 client := prsn.NewPersonClient(conn)
 person := &prsn.PersonRequest{
   Id:    1001,
   Name:  "Reddy",
   Email: "reddy@xyz.com",
   Phone: "9898982929",
   Addresses: []*prsn.PersonRequest_Address{
     &prsn.PersonRequest_Address{
       Street:            "Tripilcane",
       City:              "Chennai",
       State:             "TN",
       Zip:               "600002",
       IsShippingAddress: false,
     },
     &prsn.PersonRequest_Address{
       Street:            "Balaji colony",
       City:              "Tirupati",
       State:             "AP",
       Zip:               "517501",
       IsShippingAddress: true,
     },
   },
 }
 // Create a new person
 createPerson(client, person)
 person = &prsn.PersonRequest{
   Id:    1002,
   Name:  "Raj",
   Email: "raj@xyz.com",
   Phone: "5000510001",
   Addresses: []*prsn.PersonRequest_Address{
     &prsn.PersonRequest_Address{
       Street:            "Marathahalli",
       City:              "Bangalore",
       State:             "KS",
       Zip:               "560037",
       IsShippingAddress: true,
     },
   },
 }
 // Create a new person
 createPerson(client, person)
 // Filter with an empty Keyword
 filter := &prsn.PersonFilter{Keyword: ""}
 getPersons(client, filter)
}

 

For running the gRPC server , we have to run main.go from the directory – server

go run main.go

 

And for testing RPC method , we have to run main.go from the directory- client

And you can view the output.

 

Hope this article helped you to build High-performance APIs in Go.

We offer Golang development services for building world-class enterprise apps. We have expertise in building most complex software solutions using Google’s Go language. Chat with us now and hire golang developers within 72 hours.

Turn your vision to magnificent reality With
Our Web and Mobile Solutions