Learning about gRPC and protobuf
gRPC
RPC (Remote Procedure Call)
- A form of inter-process communication and a technology for communication between distributed computers
- Invoking functions/methods on a remote server
- In the context of HTTP API, it involves putting methods in the URL and arguments in the query string or body
- RPC APIs use the approach {“id”:1}DELETE/resource/1 instead of the REST approach
- It can be implemented as RPC-XML and RPC-JSON
Stub
- A core concept in RPC
- The server and client use different address spaces, so it is necessary to convert the parameters used in function calls
- Otherwise, pointers to memory parameters will point to different data
- A layer that converts objects to messages and vice versa
- Divided into Client Stub and Server Stub
- The Client Stub is responsible for converting parameters in function calls and converting results delivered from the server after function execution
- The server stub is responsible for reverse-converting the parameters delivered by the client and the results of function execution
Microservices
- The advantage of a monolithic architecture is that it is easy to perform tasks such as logging, performance monitoring, and caching because the unit is one. However, as the scale grows, it becomes difficult to maintain and expand
- Another important disadvantage of monolithic is that it is limited to a single technology. Adopting a new framework or language may require rewriting the entire system
- Microservices is an architectural and organizational approach to software development where software is composed of small, independent services that communicate through well-defined APIs
- It enables easy scaling of applications, accelerates development speed to realize innovation, and shortens the release time of new features
REST API
- A web architecture that uses the HTTP protocol
- REST is a client-server relationship where backend data is provided to the client through simple representations like JSON/XML
gRPC
- A high-performance RPC framework developed by Google that can run in any environment
- Built on top of HTTP/2, it supports bidirectional communication along with existing request-response
- Supports various languages
- By default, it uses protobuf to serialize structured data, offering better performance than text-based formats like JSON
- Reduces communication costs
- Rich built-in features (authentication), supports two authentication mechanisms (SSL, Token)
- A better alternative to REST APIs for microservice architectures
- gRPC can be considered a great option when it involves idiomatic APIs or multilingual communication with large-scale microservice communication
Components
Advantages
- Can be built based on various languages
- Constructs runtime and development environments
- Enables bidirectional streaming communication based on HTTP/2
- Lighter and faster communication speed than JSON-based
- Supports various languages and platforms
- Enables bidirectional streaming
Disadvantages
- Cannot directly call gRPC services from a browser (proxy)
- Requires more code to ensure stability, as it has lower stability compared to REST APIs
- Increases complexity of the development process, difficult to maintain
- Unlike REST APIs, messages are delivered in binary, making testing difficult
Structure
- Application Layer
- Framework Layer
- Transport Layer
Channel
Stream
- When a single RPC call is invoked, this call is called a Stream, and when the RPC call starts, the Stream starts and when it ends, the Stream closes
Comparison
- gRPC-web: Composed only with gRPC
- REST: Composed by mixing gRPC or using only REST
Workflow

- Protobufs definitions
- Protoc compiler
- Generate code
- Implement
Protobuf
- A serialized data structure developed by Google and released as open source
- Serialization is the act of storing data in the form of a binary stream for file storage or network transmission
- Supports up to 64M per file
- It is possible to convert JSON files to the protocol buffer file format, and vice versa, protocol buffer files can also be converted to JSON
- When communicating with protobuf, if the value is the same as the default value, it is not transmitted during communication
- Mainly, the Protobuf model is contained in the RequestBody of POST in the Rest server for communication
0. Syntax
- There are proto2 and proto3 in syntax.
- If this content is not present, proto2 is automatically applied
- To utilize gRPC, proto3 must be used.
1. Message Types
1
2
3
4
5
6
7
| syntax = "proto3";
message SearchRequest {
string query = 1; // String field
int32 page_number = 2; // Integer field
int32 result_per_page = 3;
}
|
- int32, int64: Positive and negative
- uint32, uint64: Unsigned 2-byte integer
- sint32, sint64: Signed 2-byte integer, more efficient than normal int32
- fixed32, fixed64: Always more efficient than uint32 when greater than 4 bytes
- sfixed32, sfixed64: Always more efficient than uint64 when greater than 8 bytes
- bool
- string
- bytes
1
2
3
4
5
| **Default values for the above**
numeric: 0
bool: false
string: null
byte: null
|
2. Message Fields
1
2
3
4
5
6
7
8
| message SearchRequest {
required string query = 1;
optional int32 page_number = 2;
repeated int32 result_per_page = 3;
}
/*
In proto3, required and optional are deprecated
*/
|
3. Field Numbers
1
2
3
4
5
6
7
8
| message SearchRequest {
reserved 3, 9, 5 to 7;
reserved "leo", "dabin";
}
/*
If a previously used field is removed in the middle and then reused later, it can cause consistency and compatibility issues
Reserve fields in advance
*/
|
- Each field has a unique number
- During encoding, field numbers 1~15 use 1 byte
- Numbers 16~2047 use 2 bytes
- Frequently occurring messages are assigned in the range 1~15
4. Service
- Defines the procedure to be called by the stub object on the client side
1
2
3
| service Chat {
rpc Login(LoginRequest) returns (Token) {}
}
|
- Service defines the form of functions that the server will provide to the client through RPC
- CamelCase is recommended for service names and RPC method names
- By giving the stream option, bidirectional streaming RPC can be implemented
1
2
3
| service User {
rpc Login(LoginRequest) returns (Token) {}
}
|
- If the client sends a single request to the server, the server returns a single response
1
2
3
| service User {
rpc Login(LoginRequest) returns (stream Token) {}
}
|
- Server Streaming RPC: If the client sends a single request to the server, the server returns a stream. The stream contains a sequence of messages
- The client reads the stream until there are no more messages
1
2
3
| service User {
rpc Login(stream LoginRequest) returns (Token) {}
}
|
- Client Streaming RPC: The client sends a sequence of messages to the server using the given stream
- The client writes all the messages and waits for the server to read and give a response
1
2
3
| service User {
rpc Login(stream LoginRequest) returns (stream Token) {}
}
|
- Bidirectional Streaming RPC: Both the client and the server send a sequence of messages using a read-write stream
- The two streams operate independently, and the client and server can read them in order
- For example, the server can write responses after reading all the client’s messages, or it can alternately read and write messages one by one
Enum
1
2
3
4
5
6
7
8
9
10
| enum Corpus {
CORPUS_UNSPECIFIED = 0;
CORPUS_UNIVERSAL = 1;
CORPUS_WEB = 2;
CORPUS_IMAGES = 3;
CORPUS_LOCAL = 4;
CORPUS_NEWS = 5;
CORPUS_PRODUCTS = 6;
CORPUS_VIDEO = 7;
}
|
Using Other Message Types
1
2
3
4
5
6
7
| message Login {
User data = 1;
}
message User {
string id = 1;
string name = 2;
}
|
- Other message types can be used as field types
Nested Types
1
2
3
4
5
6
7
| message User_Login {
message Login {
string id = 1;
string password = 2;
}
repeated Result results = 1;
}
|
- Message types can be nested
Oneof
- A feature that can be applied to the behavior and save memory when there is a message with many fields and at most one field is set at a time
- When setting a member of oneof, all other members are automatically cleared
message SampleMessage {
oneof test_oneof {
string name = 4;
SubMessage sub_message = 9;
}
}
Map Type
1
2
3
| message ExampleRequest {
map<string, string> requests = 1;
}
|
- Map can be used as a field type
Package
1
2
3
4
5
6
7
| syntax="proto3";
package grpc.sample2;
message ExampleRequest {
map<string, string> requests = 1;
}
|
- A package specifier can optionally be added to the file to avoid name conflicts between proto buf types
Example

- The back-end server is in Golang
- Each server