- 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.
8.2 KiB
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
- gRPC Documentation
- GraphQL Documentation
- Protocol Buffers
- Resilience Patterns
- Security
- Skill Source:
.cursor/skills/inter-service-communication/SKILL.md