gRPC Microservices Project

A capstone project combines the ideas from every earlier topic into one working design. An online bookstore runs as three gRPC services: Catalog, Orders, and Payments. A customer places an order, and the services cooperate to check stock, charge the card, and confirm the purchase.

Project Map

              ┌──────────────────┐
 Browser ──▶ │ Gateway (REST /  │
 Mobile  ──▶ │ gRPC Web)        │
              └────────┬─────────┘
                       │ gRPC
                       ▼
              ┌───────────────┐
              │ Orders Service│
              └───┬───────┬───┘
            gRPC  │       │  gRPC
                  ▼       ▼
        ┌──────────────┐ ┌───────────────┐
        │ Catalog Svc  │ │ Payments Svc  │
        └──────┬───────┘ └───────┬───────┘
               ▼                 ▼
          Catalog DB        Payments DB

Service Responsibilities

ServiceJobKey Methods
CatalogBooks and stock levelsListBooks, GetBook, ReserveStock
OrdersOrder workflowPlaceOrder, GetOrder
PaymentsCard chargesCharge, Refund

Each service owns its data. Orders never read the Catalog database directly. All access goes through gRPC methods, which keeps boundaries clear.

Shared Contracts

// catalog/v1/catalog.proto
service CatalogService {
  rpc ListBooks (ListBooksRequest) returns (ListBooksResponse);
  rpc ReserveStock (ReserveStockRequest) returns (ReserveStockReply);
}

// payments/v1/payments.proto
service PaymentService {
  rpc Charge (ChargeRequest) returns (ChargeReply);
}

message ChargeRequest {
  string idempotency_key = 1;
  int64  amount_cents    = 2;
  string customer_id     = 3;
}

The Order Flow

1. Customer sends PlaceOrder
2. Orders → Catalog.ReserveStock    (hold the books)
3. Orders → Payments.Charge         (take the money)
4. Orders saves the order as CONFIRMED
5. Orders replies to the customer

If Charge fails:
   Orders → Catalog.ReleaseStock    (undo the hold)
   Orders replies with the error

Orders Handler

func (s *OrderServer) PlaceOrder(ctx context.Context, req *pb.PlaceOrderRequest) (*pb.Order, error) {
  ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
  defer cancel()

  _, err := s.catalog.ReserveStock(ctx, &catalogpb.ReserveStockRequest{
    BookId: req.BookId, Quantity: req.Quantity,
  })
  if err != nil {
    return nil, err
  }

  _, err = s.payments.Charge(ctx, &paymentpb.ChargeRequest{
    IdempotencyKey: req.RequestId,
    AmountCents:    req.TotalCents,
    CustomerId:     userID(ctx),
  })
  if err != nil {
    s.catalog.ReleaseStock(context.Background(), &catalogpb.ReleaseStockRequest{BookId: req.BookId, Quantity: req.Quantity})
    return nil, err
  }

  return s.repo.SaveConfirmed(ctx, req)
}

The release call uses a fresh context on purpose. Cleanup must finish even when the original call times out.

Concepts in Use

TopicWhere It Appears
Deadlines and contextThree second timeout flows to every downstream call
Error handlingStatus codes pass back to the caller
RetriesIdempotency key makes Charge safe to retry
InterceptorsLogging, recovery, and authentication on every service
mTLSServices verify each other
AuthorizationOnly Orders may call Payments
Health checksKubernetes probes each service
ObservabilityOne trace ID spans all three services

Testing Strategy

  • Unit tests for business rules with fake repositories
  • Handler tests with in memory gRPC connections
  • Contract checks with the buf breaking change detector
  • End to end tests that run all three services in containers
  • Load tests with ghz on the PlaceOrder method

Deployment Checklist

  1. Build one container image per service.
  2. Configure addresses and secrets through environment variables.
  3. Enable TLS and client certificates between services.
  4. Register health checks and readiness probes.
  5. Expose metrics and traces to the monitoring platform.
  6. Roll out with gradual traffic shifts.

Extension Ideas

Add a Shipping service that listens to confirmed orders through a server stream. Add an Email service for receipts. Add a gateway with REST routes for the web store. Each extension practices another skill from the course.

Failure Scenarios to Practice

Real systems fail in small ways. Practice each scenario in a test environment and confirm that the design responds well.

  • Payments responds slowly, and the order call hits its deadline
  • Catalog restarts during a request, and the client retries after an UNAVAILABLE error
  • The customer cancels the call, and every downstream service stops its work
  • A retry repeats the same charge, and the idempotency key blocks a second payment

Each scenario exercises a different skill and exposes gaps in logging, timeouts, or cleanup code.

Summary

The bookstore project ties contracts, context, errors, retries, security, and observability into one system. Build it step by step, test every service alone, then test the whole flow. A finished project turns separate topics into practical skill.