zhaopinxinle.com

Mastering Unary gRPC Implementation with Golang and Unit Tests

Written on

Building a Unary gRPC Service

In this guide, we will delve into the implementation of a unary gRPC service using Golang, complete with unit testing and manual testing via grpcui.

Unary gRPC Overview

Unary gRPC represents the most basic communication method in gRPC, where a client sends a single request to the server and receives a singular response. This approach is particularly useful when clients need to transmit limited data to the server.

Creating a Unary gRPC Service

Let's develop a unary gRPC service that retrieves contact names by their numbers, and vice versa, along with a method to fetch all contacts. Before we start coding, we need to create a protocol buffer (proto) for our service.

  1. Folder Setup: Begin by creating a folder named unary. The term unary signifies the type of gRPC. You can choose any name you prefer.
  2. Directory Structure: Inside the unary folder, create three subfolders: proto, client, and server.
  3. Proto File Creation: In the proto folder, create a file named unary.proto and populate it with the necessary content. The structure of this file is detailed below, including three different request examples.

syntax = "proto3";

option go_package = "alltypes/unary/proto";

package pb;

// Model

message Contacts {

string firstname = 1;

string lastname = 2;

uint64 number = 3;

}

// Unary services

service Phone {

rpc GetContactName(GetContactNameRequest) returns (GetContactNameResponse) {}

rpc GetContactNum(GetContactNumRequest) returns (GetContactNumResponse) {}

rpc ListContacts(ListContactsRequest) returns (ListContactsResponse) {}

}

message GetContactNameRequest {

string number = 1;

}

message GetContactNameResponse {

string firstname = 1;

string lastname = 2;

}

message GetContactNumRequest {

string firstname = 1;

string lastname = 2;

}

message GetContactNumResponse {

uint64 num = 1;

string result = 2;

}

message ListContactsRequest {}

message ListContactsResponse {

int32 sum = 1;

repeated Contacts contacts = 2;

}

  1. Generating pb.go Files: Use the following command in your terminal to automatically generate the pb.go files.

protoc --go_out=. --go-grpc_opt=require_unimplemented_servers=false --go_opt=paths=source_relative

--go-grpc_out=. --go-grpc_opt=paths=source_relative

proto/unary.proto

Once you execute this command, two files, unary.pb.go and unary_grpc.pb.go, will be generated. Avoid altering these files directly; instead, modify the unary.proto file and run the command again if necessary.

  1. Creating the Server: Now, let's build the server. Inside the server folder, create a file named server.go and implement the following code.

package main

import (

"context"

"errors"

"log"

"net"

"strconv"

unary "github.com/ramseyjiang/go_mid_to_senior/pkgusages/grpc/alltypes/unary/proto"

"google.golang.org/grpc"

"google.golang.org/grpc/reflection"

)

type phoneServer struct {

unary.PhoneServer

}

func main() {

listener, err := net.Listen("tcp", "0.0.0.0:50055")

if err != nil {

_ = errors.New("failed to listen: the port")

}

log.Print("Server started")

s := grpc.NewServer()

unary.RegisterPhoneServer(s, &phoneServer{})

// Register reflection service on gRPC server.

reflection.Register(s)

if err = s.Serve(listener); err != nil {

log.Fatalf("failed to serve: %v", err)

}

}

The above implementation sets up a gRPC server that listens on port 50055.

Unit Testing the Unary gRPC Server

To verify that your server is functioning correctly, we can implement unit tests. Create a file named server_test.go in the server folder and populate it with the following code:

package main

import (

"context"

"errors"

"log"

"testing"

unary "github.com/ramseyjiang/go_mid_to_senior/pkgusages/grpc/alltypes/unary/proto"

"google.golang.org/grpc"

"google.golang.org/grpc/credentials/insecure"

"google.golang.org/grpc/test/bufconn"

)

// Server setup function for testing

func server(ctx context.Context) (client unary.PhoneClient, closer func()) {

buffer := 101024 * 1024

lis := bufconn.Listen(buffer)

baseServer := grpc.NewServer()

unary.RegisterPhoneServer(baseServer, &phoneServer{})

go func() {

if err := baseServer.Serve(lis); err != nil {

log.Printf("error serving server: %v", err)

}

}()

cc, err := grpc.Dial("localhost:50055", grpc.WithTransportCredentials(insecure.NewCredentials()))

if err != nil {

log.Printf("error connecting to server: %v", err)

}

closer = func() {

err = lis.Close()

if err != nil {

log.Printf("error closing listener: %v", err)

}

baseServer.Stop()

}

client = unary.NewPhoneClient(cc)

return

}

This setup enables you to create tests for your gRPC methods, ensuring they return the expected results.

Testing the Server with grpcui

After starting your server, you can manually test it using grpcui. Open a new terminal and run:

grpcui -plaintext 0.0.0.0:50055

This command will launch a browser window displaying all implemented gRPC methods, allowing you to verify their functionality.

Conclusion

In this tutorial, we've successfully implemented a unary gRPC service in Golang, complete with unit tests and manual verification methods using grpcui. This should provide a solid foundation for building and testing gRPC services in your applications. Happy coding!

For further learning, consider reading these related articles:

  • REST vs gRPC: Which One is More Suitable for MicroServices?
  • Using Golang to build server streaming gRPC with unit tests
  • Using Golang to build client streaming gRPC with unit tests
  • Using Golang to build a chat service using bidirectional streaming gRPC with unit tests
  • Using Golang to build TLS Unary gRPC

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

Conquering Burnout: Strategies for a Healthier Mindset

Discover effective strategies to combat burnout and enhance your mental well-being.

# Turmoil at OpenAI: A Leadership Crisis Unfolds

A look into the recent upheaval at OpenAI, detailing the unexpected ousting of Sam Altman and the implications for the future of AI.

# Embracing Change: The Transformative Power of Letting Go

Discover the importance of letting go to create space for new opportunities and personal growth in your life.

A Guide to Living Intentionally: 9 Steps for a Joyful Life

Explore nine essential steps to lead a fulfilling life filled with intention, joy, and personal growth.

The Crucial Role of Eco-Friendly Energy in Our Future

Explore the importance of eco-friendly energy sources and their impact on the environment and personal finances.

How to Maximize Your Earnings Writing on Medium in 2024

Discover how to maximize your earnings on Medium in 2024 with tips on quality content, consistency, and engagement.

The Fascinating World of Transcendental Numbers in Mathematics

Explore the intriguing realm of transcendental numbers, their significance in mathematics, and the ongoing mysteries surrounding them.

The Art of Punching: Embracing the Essence Beyond Styles

Discover how letting go of martial arts styles can lead to a unique personal expression in your practice and beyond.