Files
pos-system/docs/en/skills/inter-service-communication.md
Ho Ngoc Hai 2640b351c3 Enhance documentation with detailed diagrams and structured flows
- Added request/response flow diagrams to api-design and api-gateway-advanced skills for better visualization of processes.
- Introduced configuration loading flow in configuration-management skill to clarify the configuration process.
- Included error propagation flow in error-handling-patterns skill to illustrate error handling across layers.
- Enhanced various skills with additional diagrams to improve understanding of complex concepts.

These updates aim to provide clearer guidance and improve the overall documentation experience for developers.
2026-01-01 23:22:54 +07:00

8.2 KiB

name, description
name description
inter-service-communication Inter-service communication patterns for GoodGo microservices including gRPC, GraphQL, service-to-service authentication, protocol selection, and client patterns. Use when implementing service-to-service calls, choosing communication protocols, or building service clients.

Inter-Service Communication Patterns

When to Use This Skill

Use this skill when:

  • Implementing service-to-service communication
  • Choosing between REST, gRPC, or GraphQL protocols
  • Setting up gRPC services and clients
  • Implementing GraphQL services and resolvers
  • Implementing service-to-service authentication
  • Building resilient service clients with circuit breakers
  • Managing connection pooling for service clients
  • Implementing request/response interceptors
  • Handling service discovery for internal calls
  • Optimizing inter-service communication performance

Core Concepts

Communication Protocol Options

HTTP/REST:

  • Human-readable, easy to debug
  • Browser-compatible
  • Standard HTTP semantics
  • JSON payloads
  • Good for external APIs

gRPC:

  • Binary protocol (Protocol Buffers)
  • High performance, low latency
  • Streaming support
  • Strong typing with .proto files
  • HTTP/2 based

GraphQL:

  • Flexible query language
  • Single endpoint
  • Client-controlled data fetching
  • Strong typing with schema

Protocol Selection Guidelines

Choose protocol based on use case, performance requirements, team expertise, and ecosystem needs.

Protocol Selection Decision Tree

flowchart TD
    Start([Need Inter-Service Communication]) --> CheckExternal{External/Public API?}
    
    CheckExternal -->|Yes| UseREST[Use REST]
    CheckExternal -->|No| CheckPerformance{High Performance<br/>Required?}
    
    CheckPerformance -->|Yes| CheckStreaming{Need Streaming?}
    CheckPerformance -->|No| CheckFlexible{Need Flexible<br/>Queries?}
    
    CheckStreaming -->|Yes| UseGRPC[Use gRPC]
    CheckStreaming -->|No| CheckLowLatency{Ultra Low<br/>Latency?}
    
    CheckLowLatency -->|Yes| UseGRPC
    CheckLowLatency -->|No| UseREST
    
    CheckFlexible -->|Yes| UseGraphQL[Use GraphQL]
    CheckFlexible -->|No| UseREST
    
    UseREST --> RESTDesc["REST: External APIs<br/>Browser clients<br/>Simple CRUD"]
    UseGRPC --> GRPCDesc["gRPC: Internal services<br/>High performance<br/>Streaming support"]
    UseGraphQL --> GraphQLDesc["GraphQL: Complex queries<br/>Mobile apps<br/>Flexible data"]
    
    style UseREST fill:#e1f5ff
    style UseGRPC fill:#fff4e1
    style UseGraphQL fill:#e8f5e9

Key Patterns

Service-to-Service Call Flow

The following diagram illustrates the complete flow of a service-to-service call, including authentication, interceptors, and error handling:

sequenceDiagram
    participant ClientService as Client Service
    participant ClientLib as Service Client<br/>(HTTP/gRPC/GraphQL)
    participant Interceptor as Request<br/>Interceptor
    participant Auth as Auth<br/>Middleware
    participant TargetService as Target Service
    participant Logger as Logger
    participant Metrics as Metrics
    
    ClientService->>ClientLib: Make request
    ClientLib->>Interceptor: Add correlation ID<br/>Add service auth header<br/>Add request ID
    Interceptor->>Logger: Log request start
    Interceptor->>Metrics: Track request start
    Interceptor->>TargetService: HTTP/gRPC/GraphQL Request<br/>(with headers)
    
    TargetService->>Auth: Validate x-service-auth
    alt Invalid Auth
        Auth-->>TargetService: 403 Forbidden
        TargetService-->>ClientLib: Error Response
        ClientLib->>Logger: Log error
        ClientLib->>Metrics: Track failure
        ClientLib-->>ClientService: ServiceError
    else Valid Auth
        Auth->>TargetService: Authenticated
        TargetService->>TargetService: Process request
        TargetService-->>ClientLib: Success Response
        ClientLib->>Logger: Log success<br/>(with correlation ID)
        ClientLib->>Metrics: Track success<br/>(duration, status)
        ClientLib-->>ClientService: Response Data
    end

HTTP/REST Service Client

// Base service client with circuit breaker and interceptors
import { ServiceClient } from '../../core/clients/service-client';

const notificationClient = new ServiceClient({
  baseURL: process.env.NOTIFICATION_SERVICE_URL || 'http://notification-service:5003',
  serviceName: 'notification-service',
  timeout: 5000,
  enableCircuitBreaker: true,
});

// Usage
await notificationClient.post('/api/v1/notifications', {
  userId,
  message,
});

gRPC Service

// gRPC server implementation
import { UserGrpcServer } from './user.grpc.service';

const grpcServer = new UserGrpcServer(userService);
grpcServer.start(50051);

// gRPC client
import { GrpcClient } from '../../core/clients/grpc-client';

const userGrpcClient = new GrpcClient({
  protoPath: './proto/user_service.proto',
  packageName: 'goodgo.user.v1',
  serviceName: 'UserService',
  serverUrl: 'localhost:50051',
});

const user = await userGrpcClient.call('getUser', { user_id: '123' });

GraphQL Service

// GraphQL client
import { GraphQLServiceClient } from '../../core/clients/graphql-client';

const userGraphQLClient = new GraphQLServiceClient({
  endpoint: 'http://user-service:5002/graphql',
});

const GET_USER_QUERY = `
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      email
      name
    }
  }
`;

const user = await userGraphQLClient.query(GET_USER_QUERY, { id: '123' });

Service-to-Service Authentication

The authentication flow ensures secure communication between services:

sequenceDiagram
    participant ClientService as Client Service
    participant ServiceClient as Service Client
    participant Env as Environment<br/>Variables
    participant TargetService as Target Service
    participant AuthMiddleware as Auth<br/>Middleware
    
    ClientService->>ServiceClient: Create client instance
    ServiceClient->>Env: Read INTERNAL_API_KEY
    Env-->>ServiceClient: API Key
    
    ClientService->>ServiceClient: Make request
    ServiceClient->>ServiceClient: Auto-add x-service-auth<br/>header with API key
    
    ServiceClient->>TargetService: HTTP Request<br/>(x-service-auth: token)
    
    TargetService->>AuthMiddleware: Extract x-service-auth
    AuthMiddleware->>AuthMiddleware: Compare with<br/>INTERNAL_API_KEY
    
    alt Token Matches
        AuthMiddleware->>TargetService: Auth Success
        TargetService->>TargetService: Process request
        TargetService-->>ServiceClient: 200 OK + Data
    else Token Mismatch
        AuthMiddleware->>TargetService: Auth Failed
        TargetService-->>ServiceClient: 403 Forbidden<br/>(INVALID_SERVICE_AUTH)
        ServiceClient->>ServiceClient: Throw ServiceError
        ServiceClient-->>ClientService: Error Response
    end

Implementation

// Internal auth middleware
import { internalAuthMiddleware } from '../../middlewares/internal-auth.middleware';

router.use('/internal', internalAuthMiddleware);

// Client automatically adds auth header
const client = new ServiceClient({
  baseURL: 'http://service:5000',
  serviceName: 'service',
});
// X-Service-Auth header is added automatically

Best Practices

Protocol Selection

  • REST: External APIs, browser clients, simple CRUD
  • gRPC: Internal services, high performance, streaming
  • GraphQL: Complex queries, mobile apps, flexible data

Performance

  • Use connection pooling
  • Enable HTTP keep-alive
  • Set appropriate timeouts
  • Implement circuit breakers

Security

  • Always authenticate internal calls
  • Use TLS/mTLS
  • Store secrets securely
  • Implement rate limiting

Observability

  • Log with correlation IDs
  • Track metrics (duration, success rate)
  • Add distributed tracing
  • Monitor service health

Testing

// Mock service client
const mockClient = createMockServiceClient();
mockClient.get.mockResolvedValue({ id: '123' });

Resources