Skip to main content

Overview

Protocol: HTTP/2 with Protocol Buffers Serialization: Binary (Protocol Buffers) Endpoint: api.petstoreapi.com:443 When to Use gRPC:
  • ✅ High-performance requirements
  • ✅ Microservice-to-microservice communication
  • ✅ Strongly typed contracts needed
  • ✅ Low latency, high throughput
  • ✅ Polyglot environments (multiple languages)
When NOT to Use gRPC:
  • ❌ Browser applications (use REST/GraphQL instead)
  • ❌ Simple CRUD operations (REST is simpler)
  • ❌ Need HTTP caching (REST has better caching)

How gRPC Works

Client                           Server
    │                               │
    ├──── Unary Request ──────────>│
    │    (protobuf binary)         │
    │                              │
    │                      ┌────────┴────────┐
    │                      │ Deserialize    │
    │                      │ Process        │
    │                      │ Serialize      │
    │                      └────────┬────────┘
    │                              │
    │<──── Unary Response ─────────┤
    │    (protobuf binary)         │
Key Characteristics:
  • Binary serialization (smaller, faster)
  • HTTP/2 (multiplexing, streaming)
  • Strong typing with .proto files
  • Built-in code generation
  • Bi-directional streaming

Protocol Buffers

petstore.proto

syntax = "proto3";

package petstore.v1;

service PetService {
  rpc GetPet(GetPetRequest) returns (Pet);
  rpc ListPets(ListPetsRequest) returns (ListPetsResponse);
  rpc CreatePet(CreatePetRequest) returns (Pet);
  rpc UpdatePet(UpdatePetRequest) returns (Pet);
  rpc DeletePet(DeletePetRequest) returns (DeletePetResponse);
}

message Pet {
  string id = 1;
  string name = 2;
  Species species = 3;
  string breed = 4;
  int32 age_months = 5;
  Status status = 6;
  double adoption_fee = 7;
  string currency = 8;
}

enum Species {
  SPECIES_UNSPECIFIED = 0;
  DOG = 1;
  CAT = 2;
  RABBIT = 3;
  BIRD = 4;
  REPTILE = 5;
  OTHER = 6;
}

enum Status {
  STATUS_UNSPECIFIED = 0;
  AVAILABLE = 1;
  PENDING = 2;
  ADOPTED = 3;
  NOT_AVAILABLE = 4;
}

message GetPetRequest {
  string id = 1;
}

message ListPetsRequest {
  Species species = 1;
  Status status = 2;
  int32 page = 3;
  int32 limit = 4;
}

message ListPetsResponse {
  repeated Pet data = 1;
  Pagination pagination = 2;
}

message Pagination {
  int32 page = 1;
  int32 limit = 2;
  int32 total_items = 3;
  int32 total_pages = 4;
}

message CreatePetRequest {
  string name = 1;
  Species species = 2;
  string breed = 3;
  int32 age_months = 4;
  Status status = 5;
  double adoption_fee = 6;
  string currency = 7;
}

message UpdatePetRequest {
  string id = 1;
  Pet pet = 2;
}

message DeletePetRequest {
  string id = 1;
}

message DeletePetResponse {
  bool success = 1;
  string message = 2;
}

Code Examples

Python

import grpc
from petstore_pb2 import Pet, Species, Status, GetPetRequest, ListPetsRequest, CreatePetRequest
from petstore_pb2_grpc import PetServiceStub

# Create secure channel
credentials = grpc.ssl_channel_credentials()
channel = grpc.secure_channel('api.petstoreapi.com:443', credentials)

# Add authentication token
call_credentials = grpc.access_token_call_credentials('YOUR_JWT_TOKEN')
composite_credentials = grpc.composite_channel_credentials(credentials, call_credentials)

channel = grpc.secure_channel('api.petstoreapi.com:443', composite_credentials)
stub = PetServiceStub(channel)

# Get a pet
def get_pet(pet_id):
    request = GetPetRequest(id=pet_id)
    response = stub.GetPet(request)
    print(f"Pet: {response.name}, {Species.Name(response.species)}")
    return response

# List pets
def list_pets(species=None, status=None):
    request = ListPetsRequest(
        species=species or Species.SPECIES_UNSPECIFIED,
        status=status or Status.STATUS_UNSPECIFIED,
        page=1,
        limit=20
    )
    response = stub.ListPets(request)
    for pet in response.data:
        print(f"{pet.name} - {Species.Name(pet.species)}")
    return response

# Create a pet
def create_pet(name, species, breed, age_months):
    request = CreatePetRequest(
        name=name,
        species=species,
        breed=breed,
        age_months=age_months,
        status=Status.AVAILABLE
    )
    response = stub.CreatePet(request)
    print(f"Created pet: {response.id}")
    return response

# Usage
pet = get_pet('pet_fYrZzCW9E1WIOyGw')
pets = list_pets(species=Species.DOG, status=Status.AVAILABLE)
new_pet = create_pet('Buddy', Species.DOG, 'Golden Retriever', 24)

Go

package main

import (
	"context"
	"log"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/metadata"

	pb "path/to/protos/petstore/v1"
)

func main() {
	// Create secure connection
	creds := credentials.NewTLS(nil)
	conn, err := grpc.Dial("api.petstoreapi.com:443",
		grpc.WithTransportCredentials(creds),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	client := pb.NewPetServiceClient(conn)

	// Add authentication
	ctx := metadata.AppendToOutgoingContext(context.Background(),
		"authorization", "Bearer YOUR_JWT_TOKEN")

	// Get pet
	ctx, cancel := context.WithTimeout(ctx, time.Second*5)
	defer cancel()

	pet, err := client.GetPet(ctx, &pb.GetPetRequest{
		Id: "pet_fYrZzCW9E1WIOyGw",
	})
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("Pet: %s, %s", pet.Name, pet.Species)

	// List pets
	pets, err := client.ListPets(ctx, &pb.ListPetsRequest{
		Species: pb.Species_DOG,
		Status:  pb.Status_AVAILABLE,
		Page:    1,
		Limit:   20,
	})
	if err != nil {
		log.Fatal(err)
	}

	for _, p := range pets.Data {
		log.Printf("%s - %s", p.Name, p.Species)
	}
}

Java

import io.grpc.*;
import io.grpc.stub.StreamObserver;
import petstore.v1.*;

public class PetstoreClient {
    private final PetServiceGrpc.PetServiceBlockingStub blockingStub;

    public PetstoreClient(String host, int port, String token) {
        // Create secure channel
        ManagedChannel channel = ManagedChannelBuilder.forAddress(host, port)
            .useTransportSecurity()
            .build();

        // Add authentication
        Metadata metadata = new Metadata();
        Metadata.Key<String> apiKey = Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);
        metadata.put(apiKey, "Bearer " + token);

        blockingStub = MetadataUtils.attachHeaders(
            PetServiceGrpc.newBlockingStub(channel),
            metadata
        );
    }

    public Pet getPet(String id) {
        GetPetRequest request = GetPetRequest.newBuilder()
            .setId(id)
            .build();

        Pet response = blockingStub.getPet(request);
        System.out.println("Pet: " + response.getName() + ", " + response.getSpecies());
        return response;
    }

    public void listPets() {
        ListPetsRequest request = ListPetsRequest.newBuilder()
            .setSpecies(Pet.Species.DOG)
            .setStatus(Pet.Status.AVAILABLE)
            .setPage(1)
            .setLimit(20)
            .build();

        ListPetsResponse response = blockingStub.listPets(request);

        for (Pet pet : response.getDataList()) {
            System.out.println(pet.getName() + " - " + pet.getSpecies());
        }
    }

    public static void main(String[] args) {
        PetstoreClient client = new PetstoreClient(
            "api.petstoreapi.com",
            443,
            "YOUR_JWT_TOKEN"
        );

        Pet pet = client.getPet("pet_fYrZzCW9E1WIOyGw");
        client.listPets();
    }
}

C#

using Grpc.Core;
using Grpc.Net.Client;
using Petstore.V1;

class Program
{
    static async Task Main(string[] args)
    {
        // Create channel
        var channel = GrpcChannel.ForAddress("https://api.petstoreapi.com");

        // Create client with authentication
        var headers = new Metadata
        {
            { "Authorization", "Bearer YOUR_JWT_TOKEN" }
        };

        var client = new PetService.PetServiceClient(channel);

        // Get pet
        var pet = await client.GetPetAsync(
            new GetPetRequest { Id = "pet_fYrZzCW9E1WIOyGw" },
            headers
        );

        Console.WriteLine($"Pet: {pet.Name}, {pet.Species}");

        // List pets
        var pets = await client.ListPetsAsync(
            new ListPetsRequest
            {
                Species = Species.Dog,
                Status = Status.Available,
                Page = 1,
                Limit = 20
            },
            headers
        );

        foreach (var p in pets.Data)
        {
            Console.WriteLine($"{p.Name} - {p.Species}");
        }
    }
}

Node.js

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const path = require('path');

// Load proto file
const packageDefinition = protoLoader.loadSync('petstore.proto', {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true
});

const proto = grpc.loadPackageDefinition(packageDefinition).petstore.v1;

// Create client
const credentials = grpc.credentials.createSsl();
const client = new proto.PetService('api.petstoreapi.com:443', credentials);

// Add authentication metadata
const metadata = new grpc.Metadata();
metadata.add('authorization', 'Bearer YOUR_JWT_TOKEN');

// Get pet
client.getPet({ id: 'pet_fYrZzCW9E1WIOyGw' }, metadata, (err, response) => {
  if (err) {
    console.error(err);
    return;
  }

  console.log(`Pet: ${response.name}, ${response.species}`);
});

// List pets
client.listPets({
  species: 'DOG',
  status: 'AVAILABLE',
  page: 1,
  limit: 20
}, metadata, (err, response) => {
  if (err) {
    console.error(err);
    return;
  }

  response.data.forEach(pet => {
    console.log(`${pet.name} - ${pet.species}`);
  });
});

Streaming

Server Streaming

service PetService {
  rpc StreamPets(ListPetsRequest) returns (stream Pet);
}
# Server streaming
for pet in stub.StreamPets(ListPetsRequest()):
    print(f"Received: {pet.name}")

Client Streaming

service PetService {
  rpc CreatePets(stream CreatePetRequest) returns (CreatePetsResponse);
}
# Client streaming
def create_pets_generator():
    yield CreatePetRequest(name='Buddy', species=Species.DOG)
    yield CreatePetRequest(name='Whiskers', species=Species.CAT)
    yield CreatePetRequest(name='Max', species=Species.DOG)

response = stub.CreatePets(create_pets_generator())
print(f"Created {response.count} pets")

Bidirectional Streaming

service ChatService {
  rpc ChatStream(stream ChatMessage) returns (stream ChatMessage);
}

Authentication

Metadata Token

credentials = grpc.access_token_call_credentials('YOUR_JWT_TOKEN')
composite_credentials = grpc.composite_channel_credentials(
    ssl_credentials,
    credentials
)

Per-Call Authentication

# Add metadata to specific call
metadata = [('authorization', 'Bearer YOUR_TOKEN')]
response = stub.GetPet(request, metadata=metadata)

Error Handling

from grpc import StatusCode

try:
    response = stub.GetPet(GetPetRequest(id='invalid_id'))
except grpc.RpcError as e:
    if e.code() == StatusCode.NOT_FOUND:
        print("Pet not found")
    elif e.code() == StatusCode.PERMISSION_DENIED:
        print("Access denied")
    elif e.code() == StatusCode.INVALID_ARGUMENT:
        print("Invalid argument")
    else:
        print(f"Error: {e.code()} - {e.details()}")

Best Practices

1. Reuse Channels

# Good - reuse channel
channel = grpc.secure_channel('api.petstoreapi.com:443', credentials)
stub = PetServiceStub(channel)

# Make multiple calls
pet1 = stub.GetPet(request1)
pet2 = stub.GetPet(request2)

2. Set Deadlines

from datetime import timedelta

try:
    response = stub.GetPet(
        request,
        timeout=timedelta(seconds=5)
    )
except grpc.RpcError as e:
    if e.code() == StatusCode.DEADLINE_EXCEEDED:
        print("Request timed out")

3. Handle Retries

from grpc import Retry

retry_policy = Retry(
    initial=1.0,  # Initial backoff in seconds
    multiplier=2.0,  # Backoff multiplier
    max=10.0,  # Maximum backoff in seconds
    per_retry_timeout=1.0
)

response = stub.GetPet(
    request,
    retry=retry_policy,
    timeout=timedelta(seconds=30)
)

Comparison with REST

FeaturegRPCREST
SerializationBinary (Protobuf)Text (JSON)
PerformanceVery HighMedium
Code Generation✅ Built-in⚠️ Third-party
Streaming✅ Bidirectional⚠️ SSE only
Browser Support⚠️ Requires grpc-web✅ Native
Contract.proto fileOpenAPI/Swagger
Payload SizeSmallLarge
Learning CurveSteeperEasier

Troubleshooting

Connection Issues

  • Verify TLS certificate
  • Check firewall rules
  • Ensure correct port (443)
  • Verify DNS resolution

Performance Issues

  • Reuse channels (don’t recreate)
  • Use streaming for bulk operations
  • Implement proper retry logic
  • Monitor gRPC metrics

Interactive Documentation