Building a gRPC Server in Go
Tags: go, grpc, webdev, tutorial
Published: 2022-02-24 11:27:31

---
title: Building a gRPC Server in Go
published: true
date: 2022-02-24 11:27:00 UTC
tags: go, grpc, webdev, tutorial
canonical_url: https://sahansera.dev/building-grpc-server-go/
cover_image: https://sahansera.dev/static/77959124eae2723b1574c631212ed835/dcbba/building-grpc-server-go.webp
---

## Intro

In this article, we will create a simple web service with gRPC in Go. We won’t use any third-party tools and only create a single endpoint to interact with the service to keep things simple.

## Motivation

This is the second part of an articles series on gRPC. If you want to jump ahead, please feel free to do so. The links are down below.

- [Introduction to gRPC](https://sahansera.dev/introduction-to-grpc/)
- [Building a gRPC server with Go](https://sahansera.dev/building-grpc-server-go/) (You are here)
- [Building a gRPC client with .NET](https://sahansera.dev/building-grpc-server-dotnet/)
- [Building a gRPC client with Go](https://sahansera.dev/building-grpc-client-go)
- [Building a gRPC client with .NET](https://sahansera.dev/building-grpc-client-dotnet)

Please note that this is intended for anyone who’s interested in getting started with gRPC. If you’re not, please feel free to skip this article.

## The plan

So this is what we are trying to achieve.

1. Generate the `.proto` IDL stubs.
2. Write the business logic for our service methods.
3. Spin up a gRPC server on a given port.

In a nutshell, we will be covering the following items on our initial diagram.

![building-grpc-server-go-1.png](https://sahansera.dev/static/c1481df614d654fbbcaede50e8cf20db/5a190/building-grpc-server-go-1.png "building-grpc-server-go-1.png")

> 💡 As always, all the code samples documentation can be found at: [https://github.com/sahansera/go-grpc](https://github.com/sahansera/go-grpc)

## Prerequisites

This guide targets Go and assumes you have the necessary go tools installed locally. Other than that, we will cover gRPC specific tooling down below. Please note that I’m using some of the commands that are macOS specific. Please follow this [link](https://grpc.io/docs/languages/go/quickstart/) to set it up if you are on a different OS.

To install Protobuf compiler:

```bash
brew install protobuf
```

To install Go specific gRPC dependencies:

```bash
go install http://google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
go install http://google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
```

## Project structure

There is no universally agreed-upon project structure per se. We will use Go modules and start by initializing a new project. So our business problem is this - we have a bookstore and we want to expose its inventory via an RPC function.

Since this talks about the creation of the server, we will call it `bookshop/server`

We can create a new folder called `server` for the server and initialize it by so:

```bash
go mod init bookshop/server
```

In a later post, we will also work on the client-side of this app and call it `bookshop/client`

This is what it’s going to look like at the end of this post.

![building-grpc-server-go-2.png](https://sahansera.dev/static/b6da05025f4b88f31d960e3ccf8ef1fa/9b7bd/building-grpc-server-go-2.png "building-grpc-server-go-2.png")

## Creating the service definitions with .proto files

In my previous post, we discussed what are Protobufs and how to write one. We will be using the same example which is shown below.

A common pattern to note here is to keep your `.proto` files in their separate folder, so that use them to generate the server and client stubs.

[bookshop.proto](https://github.com/sahansera/go-grpc/blob/main/proto/bookshop.proto)

```protobuf
syntax = "proto3";

option go_package = "bookshop/pb";

message Book {
  string title = 1;
  string author = 2;
  int32 page_count = 3;
  optional string language = 4;
}

message GetBookListRequest {}
message GetBookListResponse { repeated Book books = 1; }

service Inventory {
  rpc GetBookList(GetBookListRequest) returns (GetBookListResponse) {}
}
```

Note how we have used the [option](https://developers.google.com/protocol-buffers/docs/proto#options) keyword here. We are essentially saying the Protobuf compiler where we want to put the generated stubs. You can have multiple option statements depending on which languages you are using to generate the stubs for.

> 💡 You can find a full list of allowed values at [google/protobuf/descriptor.proto](https://github.com/protocolbuffers/protobuf/blob/2f91da585e96a7efe43505f714f03c7716a94ecb/src/google/protobuf/descriptor.proto#L44)

Other than that, we have 3 messages to represent a Book entity, a request and a response, respectively. Finally we have a service defined called `Inventory` which has a RPC named `GetBookList` which can be called by the clients.

If you need to understand how this is structured, please refer to my previous [post](https://sahansera.dev/introduction-to-grpc/) 🙏

## Generating the stubs

Now that we have the IDL created we can generate the Go stubs for our server. It is a good practice to put it under the `make gen` command so that we can easily generate them with a single command in the future.

```bash
protoc --proto_path=proto proto/*.proto --go_out=. --go-grpc_out=.
```

Once this is done, you will see the generated files under the `server/pb` folder.

![building-grpc-server-go-3.png](https://sahansera.dev/static/71fe5723f87eb928195ad96244feee60/045fd/building-grpc-server-go-3.png "building-grpc-server-go-3.png")

Awesome! 🎉 now we can use these subs in our server to respond to any incoming requests.

## Creating the gRPC server

Now, we will create the main.go file to create the server.

[main.go](https://github.com/sahansera/go-grpc/blob/main/server/main.go)

```go
...

type server struct {
	pb.UnimplementedInventoryServer
}

func (s *server) GetBookList(ctx context.Context, in *pb.GetBookListRequest) (*pb.GetBookListResponse, error) {
	return &pb.GetBookListResponse{
		Books: getSampleBooks(),
	}, nil
}

func main() {
	listener, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}

	s := grpc.NewServer()
	pb.RegisterInventoryServer(s, &server{})
	if err := s.Serve(listener); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}
...
```

1. We first define a struct to represent our server. The reason why we need to [embed](https://go.dev/doc/effective_go#embedding) `pb.UnimplementedInventoryServer` is to maintain future compatibility when generating gRPC bindings for Go. You can read more on this in this initial [proposal](https://github.com/grpc/grpc-go/issues/3669) and on [README](https://github.com/grpc/grpc-go/blob/master/cmd/protoc-gen-go-grpc/README.md).
2. As we discussed, `GetBookList` can be called by the clients, and this is where that request will be handled. We have access to context (such as auth tokens, headers etc.) and the request object we defined.
3. In the `main` method, we are creating a listening on TCP port 8080 with the `net.Listen` method, initialize a new gRPC server instance, register our Inventory service and then start responding to incoming requests.

## Interacting with the Server

Usually, when interacting with the HTTP/1.1-like server, we can use cURL to make requests and inspect the responses. However, with gRPC, we can’t do that. (you can make requests to HTTP/2 services, but those won’t be readable). We will be using [gRPCurl](https://github.com/fullstorydev/grpcurl) for that.

Once you have it up and running, you can now interact with the server we just built.

```bash
grpcurl -plaintext localhost:8080 Inventory/GetBookList
```

> 💡 Note: gRPC defaults to TLS for transport. However, to keep things simple, I will be using the `-plaintext` flag with `grpcurl` so that we can see a human-readable response.

![building-grpc-server-go-4.png](https://sahansera.dev/static/f9ac764800043e617a828c66ae06f036/5a190/building-grpc-server-go-4.png "building-grpc-server-go-4.png")

How do we figure out the endpoints of the service? There are two ways to do this. One is by providing a path to the proto files, while the other option enables reflection through the code.

**Enabling reflection**

This is a pretty cool feature, where it will give you introspection capabilities to your API.

```go
reflection.Register(gs)
```

Following screenshot displays some of the commands you can use to introspect the API.

![building-grpc-server-go-5.png](https://sahansera.dev/static/883f50db1fc2b463ea65ba7129930a61/5a190/building-grpc-server-go-5.png "building-grpc-server-go-5.png")

```bash
grpcurl -plaintext -msg-template localhost:8080 describe .GetBookListResponse
```

**Using proto files**

If you don’t want to to enable it by code we can use the Protobuf files to let gRPCurl know which methods are available. Normally, when a team makes a gRPC service they will make the protobuf files available if you are integrating with them. So, without having to ask them or doing trial-and-error you can use these proto files to introspect what kind of endpoints are available for consumption.

```bash
grpcurl -import-path proto -proto bookshop.proto list
```

gRPCurl is great if you want to debug your RPC calls if you don’t have your client built yet.

## Conclusion

In this article we looked at how we can create a simple gRPC server with Go. In the next one we will learn how to do the same with .NET.

Feel free to let me know any feedback or questions. Thanks for reading ✌️

## References

- [https://medium.com/@nate510/structuring-go-grpc-microservices-dd176fdf28d0](https://medium.com/@nate510/structuring-go-grpc-microservices-dd176fdf28d0)
- [https://www.youtube.com/watch?v=RHWwMrR8LUs&ab\_channel=NicJackson](https://www.youtube.com/watch?v=RHWwMrR8LUs&ab_channel=NicJackson)
- [https://www.oreilly.com/library/view/grpc-up-and/9781492058328/](https://www.oreilly.com/library/view/grpc-up-and/9781492058328/)