Defining Services — gRPC Service Definitions with Protocol Buffers
In this tutorial, you will learn about Defining Services. We cover key concepts, practical examples, and best practices to help you master this topic.
gRPC services are defined in .proto files using the service keyword, specifying RPC methods with their request and response message types and streaming direction.
Service Definition Syntax
syntax = "proto3";
package dodatech.threat.v1;
service ThreatService {
// Unary
rpc GetThreat(GetThreatRequest) returns (Threat);
rpc CreateThreat(CreateThreatRequest) returns (Threat);
// Server streaming
rpc ListThreats(ListThreatsRequest) returns (stream Threat);
// Client streaming
rpc SubmitThreats(stream SubmitThreatRequest) returns (SubmitSummary);
// Bidirectional streaming
rpc MonitorThreats(stream MonitorRequest) returns (stream ThreatAlert);
}
Implementing a Service
class ThreatServiceServicer(threat_pb2_grpc.ThreatServiceServicer):
def GetThreat(self, request, context):
threat = db.get_threat(request.id)
if not threat:
context.abort(grpc.StatusCode.NOT_FOUND, "Threat not found")
return threat_pb2.Threat(
id=threat.id,
name=threat.name,
severity=threat.severity,
)
def ListThreats(self, request, context):
threats = db.list_threats(severity=request.severity, limit=request.limit)
for threat in threats:
yield threat_pb2.Threat(
id=threat.id,
name=threat.name,
severity=threat.severity,
)
Common Mistakes
1. Forgetting the stream Keyword
Omitting stream creates a unary RPC instead of streaming. The method signature changes completely.
2. Overloading One Service
A service with 50+ methods is hard to maintain. Split into focused services: DeviceService, ThreatService, UserService.
3. Not Documenting RPC Methods
Use comments in proto files. They appear in generated code and documentation.
4. Making Methods Too Coarse
One RPC that does everything (GetOrCreateAndUpdate) is an anti-pattern. Each RPC should do one thing.
5. Ignoring Deadline Propagation
gRPC clients can set deadlines. Services should check context.is_active() to respect timeouts.
Practice Questions
- How do you define a server streaming RPC?
- What is the difference between
rpc Foo(Bar) returns (Baz)andreturns (stream Baz)? - How do you organize services in a large project?
- What happens when an RPC returns an error?
- Can a service have no methods?
Answers:
- Add
streambefore the return type:rpc ListThreats(Request) returns (stream Threat). - Without stream: unary RPC (single response). With stream: server sends multiple responses over time.
- Split by domain (DeviceService, ThreatService) and split large services when they exceed 10-15 methods.
- The server calls
context.abort(status_code, message)or returns an error. The client receives a gRPC error with the status code. - Yes — but it's not useful. An empty service definition still generates code but has no RPC methods.
Mini Project
Define gRPC services for DodaTech's complete API. Create DeviceService (CRUD + streaming updates), ThreatService (CRUD + real-time alerts), ScanService (manage scans + progress streaming), and UserService (auth + profile management).
What's Next
| Topic | Description |
|---|---|
| Code Gen | Generating client/server code |
| Unary RPC | Request-response RPC pattern |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro