Files
pos-system/.agent/rules/inter-service-communication.md

5.9 KiB

trigger
trigger
always_on

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

Protocol Comparison

Protocol Use Case Latency Complexity Best For
REST External APIs, CRUD Medium Low Browser clients, simple APIs
gRPC Internal high-perf Low High Service-to-service, streaming
GraphQL Flexible queries Medium Medium Mobile apps, complex data

Protocol Selection Guidelines

External/Public API       → REST
Internal service-to-service → gRPC (performance) or REST (simplicity)
Complex data fetching     → GraphQL
Real-time streaming       → gRPC or WebSocket

HTTP/REST Client Pattern

import axios from 'axios';

const client = axios.create({
  baseURL: process.env.USER_SERVICE_URL,
  timeout: 5000,
  headers: {
    'Content-Type': 'application/json',
    'x-service-auth': process.env.INTERNAL_API_KEY,
  },
});

// Add correlation ID for tracing
client.interceptors.request.use((config) => {
  config.headers['x-correlation-id'] = generateCorrelationId();
  return config;
});

gRPC Pattern

Proto Definition

syntax = "proto3";
package goodgo.user.v1;

service UserService {
  rpc GetUser(GetUserRequest) returns (GetUserResponse);
  rpc StreamUserUpdates(StreamRequest) returns (stream UserUpdate);
}

message GetUserRequest { string user_id = 1; }
message GetUserResponse { User user = 1; }

Client Usage

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

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

GraphQL Pattern

Client Usage

const client = new GraphQLClient(process.env.USER_SERVICE_GRAPHQL_URL, {
  headers: { 'x-service-auth': process.env.INTERNAL_API_KEY },
});

const GET_USER = `query GetUser($id: ID!) { user(id: $id) { id email name } }`;
const data = await client.request(GET_USER, { id: '123' });

Service Authentication

Internal Auth Middleware

export const internalAuthMiddleware = (req, res, next) => {
  const token = req.headers['x-service-auth'];

  if (token !== process.env.INTERNAL_API_KEY) {
    return res.status(403).json({
      success: false,
      error: { code: 'INVALID_SERVICE_AUTH', message: 'Invalid authentication' }
    });
  }

  next();
};

Essential Headers

Header Purpose
x-service-auth Internal authentication token
x-correlation-id Request tracing across services
x-request-id Unique request identification

Best Practices

Performance Optimization

  • Connection Pooling: Reuse HTTP connections
  • Keep-Alive: Enable persistent connections
  • Compression: Use gzip for HTTP responses
  • Timeouts: Always set appropriate timeouts
  • Circuit Breaker: Prevent cascade failures

Security

  • Service Authentication: Always authenticate internal calls
  • TLS/mTLS: Use TLS for all communication
  • Secrets Management: Use environment variables
  • Rate Limiting: Implement for service clients

Observability

  • Logging: Log all calls with correlation IDs
  • Metrics: Track duration, success rate, errors
  • Tracing: Add distributed tracing
  • Health Checks: Monitor service health

Common Mistakes

  1. No Service Authentication

    // BAD: No auth header
    await client.get('/api/users');
    
    // GOOD: Include service auth
    await client.get('/api/users', {
      headers: { 'x-service-auth': process.env.INTERNAL_API_KEY }
    });
    
  2. Missing Timeouts

    // BAD: No timeout
    await axios.get(url);
    
    // GOOD: Set timeout
    await axios.get(url, { timeout: 5000 });
    
  3. No Circuit Breaker

    // GOOD: Use circuit breaker for external calls
    await circuitBreaker.fire(() => serviceClient.get('/api/users'));
    
  4. Hardcoded Service URLs

    // BAD
    const url = 'http://user-service:5000';
    
    // GOOD
    const url = process.env.USER_SERVICE_URL;
    

Quick Reference

HTTP Client Setup:

const client = axios.create({
  baseURL: process.env.SERVICE_URL,
  timeout: 5000,
  headers: { 'x-service-auth': process.env.INTERNAL_API_KEY }
});

gRPC Client Setup:

const client = new GrpcClient({
  protoPath: './proto/service.proto',
  serviceName: 'UserService',
  serverUrl: 'localhost:50051'
});

GraphQL Client Setup:

const client = new GraphQLClient(endpoint, {
  headers: { 'x-service-auth': process.env.INTERNAL_API_KEY }
});

Error Classes:

ServiceUnavailableError  // Service is down
ServiceTimeoutError      // Request timeout
ServiceError             // Generic service error

Resources