Skip to content

gRPC Unary RPC — Synchronous Request-Response Communication

DodaTech Updated 2026-06-28 2 min read

In this tutorial, you will learn about grpc unary rpc. We cover key concepts, practical examples, and best practices to help you master this topic.

Unary RPC is the simplest gRPC pattern — a single request message from the client elicits a single response message from the server, similar to a REST API call.

What You'll Learn

You will learn how to implement unary RPCs on server and client, handle errors, set deadlines, and follow best practices for synchronous gRPC communication.

Unary RPC Definition

service DeviceService {
  rpc GetDevice(GetDeviceRequest) returns (Device);
  rpc CreateDevice(CreateDeviceRequest) returns (Device);
  rpc UpdateDevice(UpdateDeviceRequest) returns (Device);
  rpc DeleteDevice(DeleteDeviceRequest) returns (DeleteDeviceResponse);
}

message GetDeviceRequest { string id = 1; }
message CreateDeviceRequest {
  string name = 1;
  string os = 2;
  string user_id = 3;
}

Server Implementation

class DeviceServiceServicer(device_pb2_grpc.DeviceServiceServicer):
    def GetDevice(self, request, context):
        device = db.get_device(request.id)
        if not device:
            context.abort(grpc.StatusCode.NOT_FOUND, f"Device {request.id} not found")
        
        return device_pb2.Device(
            id=device.id,
            name=device.name,
            os=device.os,
            status=device_pb2.ONLINE,
        )
    
    def CreateDevice(self, request, context):
        if not request.name or not request.os:
            context.abort(grpc.StatusCode.INVALID_ARGUMENT, "name and os required")
        
        device = db.create_device(name=request.name, os=request.os, user_id=request.user_id)
        return device_pb2.Device(
            id=device.id,
            name=device.name,
            os=device.os,
        )

Client Implementation

import grpc
import device_pb2
import device_pb2_grpc

def run():
    channel = grpc.insecure_channel("localhost:50051")
    stub = device_pb2_grpc.DeviceServiceStub(channel)
    
    # Simple call
    device = stub.GetDevice(device_pb2.GetDeviceRequest(id="dev-001"))
    print(f"Device: {device.name} ({device.os})")
    
    # Call with deadline
    try:
        device = stub.GetDevice(
            device_pb2.GetDeviceRequest(id="dev-001"),
            timeout=5.0  # 5 second deadline
        )
    except grpc.RpcError as e:
        print(f"gRPC error: {e.code().name}{e.details()}")
    
    # Create device
    new_device = stub.CreateDevice(
        device_pb2.CreateDeviceRequest(name="Office-PC", os="Windows 11", user_id="user-001")
    )
    print(f"Created: {new_device.id}")

if __name__ == "__main__":
    run()

Common Mistakes

1. Not Handling gRPC Status Codes

Always catch grpc.RpcError and check e.code(). Different codes need different handling (NOT_FOUND, UNAVAILABLE, DEADLINE_EXCEEDED).

2. No Timeouts on Client Calls

Without timeouts, a stuck server holds client resources indefinitely. Always set timeout on client calls.

3. Blocking in Server Handlers

Long-running operations in unary handlers block the thread pool. Use async handlers or offload to worker threads.

4. Returning Wrong Status Codes

Validation errors should return INVALID_ARGUMENT. Missing resources return NOT_FOUND. Use the correct gRPC status code.

5. Not Validating Input

Client requests may contain invalid data. Always validate input in server handlers before processing.

Practice Questions

  1. What is a unary RPC?
  2. How do you set a deadline on a client call?
  3. How do you return errors from a server handler?
  4. What status code should you use for invalid input?
  5. Why should you validate input in server handlers?

Answers:

  1. A unary RPC is a single request followed by a single response — the simplest gRPC pattern, analogous to HTTP request-response.
  2. Pass timeout=seconds to the stub method or set a deadline on the channel.
  3. Call context.abort(grpc.StatusCode, "message") or return an error from the handler.
  4. INVALID_ARGUMENT for invalid input, NOT_FOUND for missing resources, UNAUTHENTICATED for auth failures.
  5. Clients may send invalid or malicious data. Always validate at the server boundary regardless of client-side validation.

Mini Project

Build a unary gRPC service for DodaTech's device management. Include GetDevice, CreateDevice, UpdateDevice, and DeleteDevice with proper error handling, input validation, and client timeouts.

What's Next

Topic Description
Server Streaming One request, stream of responses
Client Streaming Stream of requests, one response
⬅ Code Generation
➡ Server Streaming

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro