What is gRPC?
- gRPC is a protocol developed by Google to implement RPC.
- It uses Protocol Buffers to serialize data, enabling high-speed communication.
- API specifications are pre-defined in a
.proto
file using IDL, from which source code for both the server and client sides is generated.
Differences between REST and gRPC
- REST is resource-oriented, whereas RPC focuses on method invocation, with data being a byproduct.
Advantages and Disadvantages
Advantages
- High performance with HTTP/2
- Data transfer via Protocol Buffers
- Development follows a schema-first approach due to the use of IDL
- Flexible streaming modes
Disadvantages
- Non-compliance with HTTP/2
- Limited browser support
- Variability in feature implementation depending on the programming language
- Serialized binary data is not human-readable
- REST is also sufficiently fast
.proto Files
gRPC uses Protocol Buffers as its serialization format.
Schema definitions are made in files with the .proto
extension, and code for various languages is generated using the protoc
command.
In Protocol Buffers, all values have types, which can be divided into scalar types and message types.
Scalar Types
- Numeric, string, boolean, byte array
Message Types
- Message types with multiple fields
- Multiple message types can be defined in a single
.proto
file
1
2
3
4
5
|
message Person {
int32 id = 1;
string name = 2;
string email = 3;
}
|
Conducting the gRPC Quick Start
This time, we will perform the gRPC Quick Start using a Python environment.
https://grpc.io/docs/languages/python/quickstart/
Set up the necessary Python environment.
1
2
|
python -m pip install grpcio
python -m pip install grpcio-tools
|
Download the sample code.
1
2
|
git clone -b v1.64.0 --depth 1 --shallow-submodules https://github.com/grpc/grpc
cd grpc/examples/python/helloworld
|
Start the server.
1
2
3
4
|
python greeter_server.py
# Output
Server started, listening on 50051
|
Open another terminal and start the client.
1
2
3
4
5
|
python greeter_client.py
## Response
Will try to greet world ...
Greeter client received: Hello, you!
|
Communication between the gRPC client and server was successfully established.
Modifying the .proto File
This time, we will modify the helloworld.proto
file to add a new method.
Move to the directory containing the helloworld.proto
file.
1
|
cd grpc/examples/protos
|
Modify the file as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
// Add the following line
rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
rpc SayHelloStreamReply (HelloRequest) returns (stream HelloReply) {}
rpc SayHelloBidiStream (stream HelloRequest) returns (stream HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
|
Generate the gRPC code.
1
2
3
|
cd examples/python/helloworld
python -m grpc_tools.protoc -I../../protos --python_out=. --pyi_out=. --grpc_python_out=. ../../protos/helloworld.proto
|
The following files are regenerated.
1
2
3
4
5
|
ls -l
-rw-r--r--@ 1 xx xx 1823 9 1 18:12 helloworld_pb2.py
-rw-r--r--@ 1 xx xx 578 9 1 18:12 helloworld_pb2.pyi
-rw-r--r--@ 1 xx xx 7018 9 1 18:12 helloworld_pb2_grpc.py
|
The _pd
file that is updated contains the auto-generated Protocol Buffers definition classes and is generally not manually modified.
Update the greeter_server.py
file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
from concurrent import futures
import logging
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return helloworld_pb2.HelloReply(message="Hello, %s!" % request.name)
# Add the following function
def SayHelloAgain(self, request, context):
return helloworld_pb2.HelloReply(message="Hello Again, %s!" % request.name)
def serve():
port = "50051"
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port("[::]:" + port)
server.start()
print("Server started, listening on " + port)
server.wait_for_termination()
if __name__ == "__main__":
logging.basicConfig()
serve()
|
Update the greeter_client.py
file.
1
2
3
4
5
6
7
8
9
10
11
|
def run():
# NOTE(gRPC Python Team): .close() is possible on a channel and should be
# used in circumstances in which the with statement does not fit the needs
# of the code.
print("Will try to greet world ...")
with grpc.insecure_channel("localhost:50051") as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(helloworld_pb2.HelloRequest(name="you"))
print("Greeter client received: " + response.message)
response = stub.SayHelloAgain(helloworld_pb2.HelloRequest(name="you"))
print("Greeter client received: " + response.message)
|
Restart the server and run the client.
1
2
3
4
5
6
|
python greeter_server.py
python greeter_client.py
# Output
Greeter client received: Hello, you!
Greeter client received: Hello Again, you!
|
The newly added method is confirmed to be functioning correctly.
Summary
This time, we researched gRPC and followed the official documentation tutorial.
gRPC allows for schema-first development and enables high-performance communication via HTTP/2. Recently, it has been gaining attention as an alternative to REST APIs, making it a technology worth familiarizing yourself with.