Skip to content

Commit babf1b4

Browse files
authored
update: README Getting Started gRPC-Go Codelab (#23)
1 parent 133d9b6 commit babf1b4

File tree

1 file changed

+347
-14
lines changed

1 file changed

+347
-14
lines changed

codelabs/grpc-go-getting-started/README.md

Lines changed: 347 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,356 @@
22

33
Get hands-on with gRPC for Go in this interactive codelab! <!-- TODO(arvindbr8): Insert link once codelab is published. -->
44

5-
6-
Perfect for Go developers new to gRPC, those seeking a refresher, or anyone building distributed systems. No prior gRPC experience needed!
7-
8-
#### Build a complete gRPC service from scratch, learning:
9-
- Protocol Buffers (protobuf): Define service contracts & data.
10-
- gRPC Code Generation: Auto-generate Go code.
11-
- Client/Server Communication: Implement seamless interactions.
12-
13-
#### You'll gain:
14-
- A working gRPC service in Go.
15-
- Hands-on experience with Protocol Buffers and code generation.
16-
- Skills to design, build, & test gRPC clients and servers.
17-
- A strong foundation in gRPC for real-world projects.
5+
Perfect for Go developers new to gRPC, those seeking a refresher, or anyone
6+
building distributed systems. No prior gRPC experience needed!
187

198
## How to use this directory
209

2110
- [start_here](start_here/) directory serves as a starting point for the
22-
codelab.
11+
codelab.
2312
- [completed](completed/) directory showcases the finished code, giving you a
2413
peak of how the final implementation should look like.
14+
15+
## Before you begin
16+
17+
### What you’ll learn
18+
19+
* Get hands-on with gRPC for Go in this interactive codelab\! Perfect for Go
20+
developers new to gRPC, those seeking a refresher, or anyone building
21+
distributed systems. No prior gRPC experience needed\!
22+
* Build a complete gRPC service from scratch, learning:
23+
* Protocol Buffers (protobuf): Define service contracts & data.
24+
* gRPC Code Generation: Auto-generate Go code.
25+
* Client/Server Communication: Implement seamless interactions.
26+
* Testing & Debugging: Ensure reliability & correctness.
27+
* You'll gain:
28+
* A working gRPC service in Go.
29+
* Hands-on experience with Protocol Buffers and code generation.
30+
* Skills to design, build, & test gRPC clients and servers.
31+
* A strong foundation in gRPC for real-world projects.
32+
33+
### What you’ll need
34+
35+
* A computer with internet connection
36+
37+
### What you'll build
38+
39+
Our example is a simple route mapping application that lets clients get
40+
information about features on their route, create a summary of their route, and
41+
exchange route information such as traffic updates with the server and other
42+
clients.
43+
44+
With gRPC we can define our service once in a `.proto` file and generate clients
45+
and servers in any of gRPC’s supported languages, which in turn can be run in
46+
environments ranging from servers inside a large data center to your own tablet
47+
— all the complexity of communication between different languages and
48+
environments is handled for you by gRPC. We also get all the advantages of
49+
working with protocol buffers, including efficient serialization, a simple IDL,
50+
and easy interface updating.
51+
52+
### Prerequisites
53+
54+
* [**Go**](https://golang.org/), any one of the **two latest major** [releases of Go](https://golang.org/doc/devel/release.html).
55+
* For installation instructions, see Go’s [Getting Started](https://golang.org/doc/install) guide.
56+
* [**Protocol buffer**](https://developers.google.com/protocol-buffers) **compiler**, `protoc`, [version 3](https://protobuf.dev/programming-guides/proto3).
57+
* For installation instructions, see [Protocol Buffer Compiler Installation](https://grpc.io/docs/protoc-installation/).
58+
* **Go plugins** for the protocol compiler:
59+
* Install the protocol compiler plugins for Go using the following commands.
60+
61+
```console
62+
# This command will install the plugin that generates code for the messages
63+
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
64+
65+
# This command installs the plugin that generates code for the services and methods
66+
go install google.golang.org/protobuf/cmd/protoc-gen-go-grpc@latest
67+
```
68+
69+
* Update your PATH so that the protoc compiler can find the plugins:
70+
71+
```sh
72+
export PATH="$PATH:$(go env GOPATH)/bin"
73+
```
74+
75+
* Use [this as a starting point](https://download-directory.github.io/?url=https%3A%2F%2Fgithub.com%2Fgrpc-ecosystem%2Fgrpc-codelabs%2Ftree%2Fmain%2Fcodelabs%2FGetting\_Started\_with\_gRPC\_Go) for this codelab.
76+
77+
## Defining protobuf messages and services
78+
79+
Our first step is to define the gRPC *service* and the method *request* and
80+
*response* types using [protocol buffers](https://protobuf.dev/overview).
81+
82+
Let’s start by defining the messages and service in [this file](start_here/routeguide/route_guide.proto).
83+
84+
### Define the proto Messages
85+
86+
Our `.proto` file contains protocol buffer message type definitions for all the
87+
request and response types used in our service methods.
88+
89+
Let’s define the `Point` message type. `Point` are represented as
90+
latitude-longitude pairs in the E7 representation. For the purpose of this
91+
codelabs, we will be using `integer` to define latitude and longitude.
92+
93+
```proto
94+
message Point {
95+
int32 latitude = 1;
96+
int32 longitude = 2;
97+
}
98+
```
99+
100+
Let’s also define the `Feature` message type. A `Feature` names something at a
101+
given point using a `string` field.
102+
103+
```proto
104+
message Feature {
105+
// The name of the feature.
106+
string name = 1;
107+
108+
// The point where the feature is detected.
109+
Point location = 2;
110+
}
111+
```
112+
113+
### Define the RouteGuide service
114+
115+
To define a service, you specify a named service in your `.proto` file:
116+
117+
```proto
118+
service RouteGuide {
119+
// Definition of the service goes here
120+
}
121+
```
122+
123+
### Define the RPC method in the service
124+
125+
Then you define `rpc` methods inside your service definition, specifying their
126+
request and response types. In this section of the codelab, let’s define
127+
`GetFeature` method that returns the named `Feature` for the given `Point.`
128+
129+
This would be Unary RPC method \- A *simple RPC* where the client sends a
130+
request to the server using the stub and waits for a response to come back, just
131+
like a normal function call.
132+
133+
```proto
134+
// Obtains the feature at a given position.
135+
rpc GetFeature(Point) returns (Feature) {}
136+
```
137+
138+
> [!TIP]
139+
> For the complete .proto file, see [routeguide/route_guide.proto](/completed/routeguide/route_guide.proto).
140+
141+
## Generating client and server code
142+
143+
Next we need to generate the gRPC client and server interfaces from our `.proto`
144+
service definition. We do this using the protocol buffer compiler `protoc` with
145+
a special gRPC Go plugin.
146+
147+
In the same directory where `route_guide.proto` is located, run the following command:
148+
149+
```sh
150+
protoc --go_out=. --go_opt=paths=source_relative \
151+
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
152+
route_guide.proto
153+
```
154+
155+
Running this command generates the following files in the [routeguide](start_here/routeguide) directory:
156+
157+
* `route_guide.pb.go`, which contains all the protocol buffer code to populate,
158+
serialize, and retrieve request and response message types.
159+
* `route_guide_grpc.pb.go`, which contains the following:
160+
* An interface type (or *stub*) for clients to call with the methods defined
161+
in the `RouteGuide` service.
162+
* An interface type for servers to implement, also with the methods defined in
163+
the `RouteGuide` service.
164+
165+
## Creating the server
166+
167+
First let’s look at how we create a `RouteGuide` server. There are two parts to
168+
making our `RouteGuide` service do its job:
169+
170+
* Implementing the service interface generated from our service definition:
171+
doing the actual “work” of our service.
172+
* Running a gRPC server to listen for requests from clients and dispatch them to
173+
the right service implementation.
174+
175+
> [!TIP]
176+
> For the complete server implementation, see [server.go](completed/server/server.go)
177+
178+
Let’s implement RouteGuide in `server/server.go`
179+
180+
### Implementing RouteGuide
181+
182+
We need to implement the generated `RouteGuideService` interface. This is how
183+
the implementation would look
184+
185+
> [!Note]
186+
> The starter code already has helper function which will load features into the routeGuideServer's savedFeatures field.
187+
188+
```go
189+
type routeGuideServer struct {
190+
...
191+
}
192+
...
193+
194+
func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {
195+
...
196+
}
197+
```
198+
199+
Let us look into the RPC implementation in detail
200+
201+
#### Unary RPC
202+
203+
The `routeGuideServer` implements all our service methods. Let’s look at
204+
`GetFeature` which just gets a `Point` from the client and returns the
205+
corresponding feature information from its database in a `Feature`.
206+
207+
```go
208+
func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {
209+
for _, feature := range s.savedFeatures {
210+
if proto.Equal(feature.Location, point) {
211+
return feature, nil
212+
}
213+
}
214+
// No feature was found, return an unnamed feature
215+
return &pb.Feature{Location: point}, nil
216+
}
217+
218+
```
219+
220+
The method is passed a context object for the RPC and the client’s `Point`
221+
protocol buffer request. It returns a `Feature` protocol buffer object with the
222+
response information and an `error`. In the method we populate the `Feature`
223+
with the appropriate information, and then `return` it along with a nil error to
224+
tell gRPC that we’ve finished dealing with the RPC and that the `Feature` can be
225+
returned to the client.
226+
227+
## Starting the server
228+
229+
Once we’ve implemented all our methods, we also need to start up a gRPC server
230+
so that clients can actually use our service. The following snippet shows how we
231+
do this for our `RouteGuide` service:
232+
233+
> [!NOTE]
234+
> port can be configured by passing in `port` flag. Defaults to `50051`
235+
236+
```go
237+
lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
238+
if err != nil {
239+
log.Fatalf("failed to listen: %v", err)
240+
}
241+
var opts []grpc.ServerOption
242+
grpcServer := grpc.NewServer(opts...)
243+
244+
s := &routeGuideServer{}
245+
s.loadFeatures()
246+
pb.RegisterRouteGuideServer(grpcServer, newServer())
247+
grpcServer.Serve(lis)
248+
```
249+
250+
To build and start a server, we:
251+
252+
1. Specify the port we want to use to listen for client requests using:
253+
`lis, err := net.Listen(...)`
254+
2. Create an instance of the gRPC server using `grpc.NewServer(...)`.
255+
3. Use `s.loadFeatures()` to load features into `s.savedFeatures`
256+
4. Register our service implementation with the gRPC server.
257+
5. Call `Serve()` on the server with our port details to do a blocking wait
258+
until the process is killed or `Stop()` is called.
259+
260+
## Creating the client
261+
262+
In this section, we’ll look at creating a Go client for our RouteGuide service.
263+
264+
> [!TIP]
265+
> For the complete server implementation, see [client.go](completed/client/client.go)
266+
267+
### Creating a stub
268+
269+
To call service methods, we first need to create a gRPC *channel* to communicate
270+
with the server. We create this by passing the server address and port number to
271+
`grpc.NewClient()` as follows:
272+
273+
> [!NOTE]
274+
> serverAddr can be configured by passing in `addr` flag. Defaults to `localhost:50051`
275+
276+
```go
277+
conn, err := grpc.NewClient("dns:///"+*serverAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
278+
if err != nil {
279+
log.Fatalf("fail to dial: %v", err)
280+
}
281+
defer conn.Close()
282+
```
283+
284+
You can use `DialOptions` to set the auth credentials (for example, TLS, GCE
285+
credentials, or JWT credentials) in `grpc.NewClient` when a service requires
286+
them. The `RouteGuide` service doesn’t require any credentials.
287+
288+
Once the gRPC *channel* is set up, we need a client *stub* to perform RPCs by
289+
making Go function calls. We get it using the `NewRouteGuideClient` method
290+
provided by the pb package generated from the example `.proto` file.
291+
292+
```go
293+
client := pb.NewRouteGuideClient(conn)
294+
```
295+
296+
### Calling service methods
297+
298+
Now let’s look at how we call our service methods. Note that in gRPC-Go, RPCs
299+
operate in a blocking/synchronous mode, which means that the RPC call waits for
300+
the server to respond, and will either return a response or an error.
301+
302+
#### Simple RPC
303+
304+
Calling the simple RPC `GetFeature` is nearly as straightforward as calling a local method.
305+
306+
```go
307+
feature, err := client.GetFeature(context.Background(), &pb.Point{409146138, -746188906})
308+
if err != nil {
309+
...
310+
}
311+
```
312+
313+
As you can see, we call the method on the stub we got earlier. In our method
314+
parameters we create and populate a request protocol buffer object (in our case
315+
`Point`). We also pass a `context.Context` object which lets us change our RPC’s
316+
behavior if necessary, such as time-out/cancel an RPC in flight. If the call
317+
doesn’t return an error, then we can read the response information from the
318+
server from the first return value.
319+
320+
```go
321+
log.Println(feature)
322+
```
323+
324+
## Try it out
325+
326+
Execute the following commands from the working directory:
327+
328+
1. Run the server:
329+
330+
```sh
331+
cd server
332+
go run .
333+
```
334+
335+
2. Run the client from another terminal:
336+
337+
```sh
338+
cd client
339+
go run .
340+
```
341+
342+
You’ll see output like this:
343+
344+
```
345+
Getting feature for point (409146138, -746188906)
346+
name:"Berkshire Valley Management Area Trail, Jefferson, NJ, USA" location:<latitude:409146138 longitude:-746188906 >
347+
Getting feature for point (0, 0)
348+
location:<>
349+
```
350+
> [!NOTE]
351+
> We’ve omitted timestamps from the client and server trace output shown in this page
352+
353+
## What’s next
354+
355+
* Learn how gRPC works in [Introduction to gRPC](https://grpc.io/docs/what-is-grpc/introduction/) and [Core concepts](https://grpc.io/docs/what-is-grpc/core-concepts/).
356+
* Work through the [Basics tutorial](https://grpc.io/docs/languages/go/basics/).
357+
* Explore the [API reference](https://grpc.io/docs/languages/go/api).

0 commit comments

Comments
 (0)