5.9 KiB
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
-
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 } }); -
Missing Timeouts
// BAD: No timeout await axios.get(url); // GOOD: Set timeout await axios.get(url, { timeout: 5000 }); -
No Circuit Breaker
// GOOD: Use circuit breaker for external calls await circuitBreaker.fire(() => serviceClient.get('/api/users')); -
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
- Detailed Reference - Full code examples and implementation details
- gRPC Documentation - Official gRPC documentation
- GraphQL Documentation - GraphQL learning resources
- Protocol Buffers - Protocol Buffer guide
- Resilience Patterns - Circuit breaker, retry patterns
- Security - Authentication, authorization patterns
- API Design - RESTful API patterns
- Project Rules - GoodGo coding standards