Chuyển đến nội dung chính

Lesson 5: Synchronous Communication — REST API & gRPC

REST API design best practices, gRPC vs Protobuf, HTTP/2 multiplexing, comparing REST vs gRPC, when to choose which one, API versioning strategies.

🏗️ Architecture — Lesson 5 Lesson 5: Synchronous Communication — REST API & gRPC

Cloud Native Microservices Architecture

Part 2: Microservices Design & Communication Patterns

xdev.asia

Lesson 5: Synchronous Communication — REST API & gRPC

Introduction

Synchronous communication is a request-response model: the client sends a request, waiting for the server to respond. REST and gRPC are the two most popular choices for internal service-to-service communication.


1. REST API

1.1 RESTful Design Principles

REST (Representational State Transfer) uses HTTP methods to manipulate resources:

GET    /api/v1/orders          → Liệt kê đơn hàng
GET    /api/v1/orders/{id}     → Chi tiết đơn hàng
POST   /api/v1/orders          → Tạo đơn hàng mới
PUT    /api/v1/orders/{id}     → Cập nhật toàn bộ
PATCH  /api/v1/orders/{id}     → Cập nhật một phần
DELETE /api/v1/orders/{id}     → Xoá đơn hàng

1.2 Best Practices

Naming conventions:

✅ /api/v1/orders                    # Noun, plural
✅ /api/v1/orders/{id}/items         # Nested resource
✅ /api/v1/orders?status=pending     # Filtering via query params

❌ /api/v1/getOrders                 # Verb in URL
❌ /api/v1/order                     # Singular
❌ /api/v1/orders/getByStatus/pending # Logic in URL

HTTP Status Codes:

2xx Success:
  200 OK              — GET, PUT, PATCH thành công
  201 Created          — POST tạo resource mới
  204 No Content       — DELETE thành công

4xx Client Error:
  400 Bad Request      — Validation error
  401 Unauthorized     — Chưa xác thực
  403 Forbidden        — Không có quyền
  404 Not Found        — Resource không tồn tại
  409 Conflict         — Trùng lặp (duplicate)
  422 Unprocessable    — Business logic error
  429 Too Many Requests — Rate limit exceeded

5xx Server Error:
  500 Internal Server Error — Lỗi server
  502 Bad Gateway           — Upstream service error
  503 Service Unavailable   — Service đang quá tải
  504 Gateway Timeout       — Upstream timeout

Pagination:

GET /api/v1/orders?page=2&per_page=20&sort=-created_at

{
  "data": [...],
  "meta": {
    "current_page": 2,
    "per_page": 20,
    "total": 150,
    "total_pages": 8
  },
  "links": {
    "first": "/api/v1/orders?page=1&per_page=20",
    "prev": "/api/v1/orders?page=1&per_page=20",
    "next": "/api/v1/orders?page=3&per_page=20",
    "last": "/api/v1/orders?page=8&per_page=20"
  }
}

1.3 API Versioning

Strategy 1: URL Path (khuyến nghị)
  /api/v1/orders
  /api/v2/orders

Strategy 2: Header
  Accept: application/vnd.myapi.v2+json

Strategy 3: Query Parameter
  /api/orders?version=2

1.4 OpenAPI / Swagger

Define the previous contract API (API First):

openapi: 3.0.3
info:
  title: Order Service API
  version: 1.0.0
paths:
  /api/v1/orders:
    post:
      summary: Create a new order
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: Order created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          description: Validation error
components:
  schemas:
    CreateOrderRequest:
      type: object
      required: [customer_id, items]
      properties:
        customer_id:
          type: string
          format: uuid
        items:
          type: array
          items:
            $ref: '#/components/schemas/OrderItem'

2. gRPC

2.1 Overview

gRPC is an RPC (Remote Procedure Call) framework developed by Google, using:

  • Protocol Buffers (Protobuf) — binary serialization
  • HTTP/2 — multiplexing, server push, header compression
Order Service                     Inventory Service
┌──────────────┐                  ┌──────────────┐
│              │  gRPC/HTTP2      │              │
│  gRPC Client │──────────────────▶  gRPC Server │
│  (generated) │  Protobuf binary │  (generated) │
│              │◀─────────────────│              │
└──────────────┘                  └──────────────┘

2.2 Protocol Buffers

Define service contract with .proto files:

syntax = "proto3";

package inventory;

option go_package = "github.com/myorg/inventory/proto";
option java_package = "com.myorg.inventory.grpc";

// Service definition
service InventoryService {
  // Unary RPC
  rpc CheckStock(StockRequest) returns (StockResponse);
  rpc ReserveItems(ReserveRequest) returns (ReserveResponse);

  // Server streaming
  rpc StreamStockUpdates(StockFilter) returns (stream StockUpdate);

  // Bidirectional streaming
  rpc SyncInventory(stream InventoryEvent) returns (stream SyncResult);
}

// Messages
message StockRequest {
  string product_id = 1;
  int32 quantity = 2;
}

message StockResponse {
  bool available = 1;
  int32 current_stock = 2;
  string warehouse_id = 3;
}

message ReserveRequest {
  string order_id = 1;
  repeated ReserveItem items = 2;
}

message ReserveItem {
  string product_id = 1;
  int32 quantity = 2;
}

message ReserveResponse {
  bool success = 1;
  string reservation_id = 2;
  google.protobuf.Timestamp expires_at = 3;
}

2.3 gRPC Communication Patterns

1. Unary RPC (Request-Response):
   Client ──request──▶ Server
   Client ◀─response── Server

2. Server Streaming:
   Client ──request──▶ Server
   Client ◀─stream 1── Server
   Client ◀─stream 2── Server
   Client ◀─stream N── Server

3. Client Streaming:
   Client ──stream 1──▶ Server
   Client ──stream 2──▶ Server
   Client ──stream N──▶ Server
   Client ◀──response── Server

4. Bidirectional Streaming:
   Client ──stream──▶ Server
   Client ◀──stream── Server
   (đồng thời, full-duplex)

2.4 Code Generation

From .proto file, automatically generate code for all languages:

# Go
protoc --go_out=. --go-grpc_out=. proto/inventory.proto

# Java
protoc --java_out=. --grpc-java_out=. proto/inventory.proto

# TypeScript
protoc --ts_out=. proto/inventory.proto

3. REST vs gRPC

CriteriaRESTgRPC
ProtocolHTTP/1.1 (or 2)HTTP/2
FormatJSON (text)Protobuf (binary)
PerformanceSlower (~2-10x)Faster
Payload sizeLarge (JSON verbose)Small (~30% of JSON)
StreamingNot nativeFull support
Code generationManual / OpenAPI codegenBuilt-in, mature
Browser supportNativeNeed gRPC-Web proxy
DebuggingHuman-readableDifficult (binary)
ToolingPostman, curl, ...grpcurl, BloomRPC
Learning curveLowAverage
ContractOptional (OpenAPI)Required (.proto)

3.1 When to choose REST?

  • External API for client/browser/mobile
  • Public API for third-party integration
  • Simple CRUD operations
  • Team is not familiar with gRPC

3.2 When to choose gRPC?

  • Internal service-to-service communication
  • High performance requirements (low latency, high throughput)
  • Streaming use cases (real-time updates, IoT)
  • Polyglot environment (many languages, need code generation)
  • Strict contract enforcement

3.3 Popular Pattern: REST outside, gRPC inside

┌──────────┐     REST/JSON     ┌──────────────┐     gRPC/Protobuf     ┌─────────────┐
│  Client  │──────────────────▶│ API Gateway  │─────────────────────▶│ Internal    │
│ (Browser)│◀──────────────────│              │◀─────────────────────│ Services    │
└──────────┘                   └──────────────┘                      └─────────────┘

4. Handling errors in Synchronous Communication

4.1 Timeout

Order Service ──request──▶ Payment Service
     │                           │
     │      (đợi response)       │
     │                           │
     │  timeout = 3 giây         │
     │                           │
     ├── Nếu < 3s: nhận response ✓
     └── Nếu > 3s: timeout error ✗
         → Retry? Circuit breaker? Fallback?

Rule: Always set a timeout for every outgoing request, never wait indefinitely.

4.2 Cascading Failure

❌ Synchronous chain dài:
Client → A → B → C → D → E
   │
   └── Nếu E chậm → D chậm → C chậm → B chậm → A chậm → Client timeout

Giải pháp:
1. Circuit Breaker (bài 18)
2. Timeout cho mỗi hop
3. Chuyển sang async khi có thể
4. Bulkhead pattern

5. API Contract Testing

Make sure the service provider and consumer agree on the API:

Consumer-Driven Contract Testing (Pact):

┌──────────────┐                    ┌──────────────┐
│ Order Service│   Pact Contract    │Payment Service│
│  (Consumer)  │◀──────────────────▶│  (Provider)  │
└──────────────┘                    └──────────────┘

1. Consumer viết test với expected request/response
2. Pact generate contract file
3. Provider verify contract
4. Nếu provider thay đổi API → contract test fail → phát hiện breaking change

6. Summary

PatternUse Case
RESTExternal API, browser, simple CRUD
gRPCInternal service comms, high performance, streaming
REST + gRPCREST for external, gRPC for internal
TimeoutsRequired for all sync calls
Contract TestingEnsure API compatibility between services

Next article: Asynchronous Communication — Message Queue, Event Streaming and when to use async instead of sync.