Client Layer
📝 Note: This guide uses generic placeholder names to be reusable across any Spring Boot microservice. Replace with your actual implementation:
{YourService}→ Your service name (e.g.,OrderService,PaymentService)BusinessService→ Your core service (e.g.,OrderService,UserService)DataService→ Your data processing service (e.g.,PaymentService,InventoryService)IntegrationService→ Your external integration (e.g.,PaymentGatewayService){RequestType}→ Your request DTO (e.g.,CreateOrderRequest){ResponseType}→ Your response DTO (e.g.,OrderResponse)
Overview
The client layer encapsulates all external HTTP API calls to downstream services. It provides clean abstraction for communicating with external systems and handles error responses, retries, and resilience patterns.
Key Principles
- Decorator Pattern: Wrap clients with decorators for error handling, logging, and metrics
- Pure API Calls: Clients only make HTTP calls - no business logic
- Error Translation: Decorators translate HTTP errors to domain exceptions
- Configuration External: All URLs, timeouts, and credentials from configuration files
- Resilience First: Implement timeouts, retries, and circuit breakers
Architecture Pattern
client/
├── skeleton/ # Client interfaces
│ └── *ApiClient.java
├── impl/ # Client implementations
│ ├── ApiConstants.java # Shared constants
│ └── *ApiClientImpl.java
├── decorator/ # Client decorators (error handling, logging)
│ └── *ApiDecorator.java
└── handler/ # Response/error handlers
└── *ResponseHandler.java
Request Flow
Service → Decorator → Client → External API
↓
Error Handling
Logging
Metrics
Detailed Guides
Design Patterns
📄 Design Patterns - Decorator, interface-implementation, adapter, facade, repository, resilience patterns (timeout, retry, circuit breaker), and configuration externalization
Best Practices
📄 Best Practices - RestTemplate/WebClient usage, custom exceptions, error handling, logging, configuration externalization, timeouts, connection pooling, constants, async processing, caching, and security
Testing
📄 Testing Guide - Unit testing with mocked RestTemplate, testing decorators, integration testing with WireMock, test data builders, testing retry logic and timeouts, coverage goals
Anti-Patterns
📄 Anti-Patterns - What to avoid: business logic in clients, swallowing exceptions, hardcoded URLs, missing timeouts, logging sensitive data, ignoring HTTP status codes, no connection pooling, disabling SSL verification
Code Examples
Core Patterns
- 📝 Decorator Pattern - Error handling and logging decorator wrapping API client
- 📝 RestTemplate Client - Proper RestTemplate configuration and usage with error handling
Quick Reference
Client Responsibilities Checklist
✅ Clients SHOULD:
- Make pure HTTP API calls only
- Throw HttpProxyCallException with status code and payload
- Use externalized configuration (@Value for URLs, timeouts)
- Implement timeouts (connect and read)
- Use connection pooling
❌ Clients SHOULD NOT:
- Contain business logic
- Swallow exceptions or return null on errors
- Have hardcoded URLs or credentials
- Transform or validate data beyond HTTP concerns
- Log sensitive information (tokens, passwords)
Decorator Responsibilities Checklist
✅ Decorators SHOULD:
- Translate HTTP errors to domain exceptions
- Add logging (DEBUG for requests, INFO for success, ERROR for failures)
- Collect metrics and performance data
- Implement circuit breakers for resilience
- Add caching when appropriate
❌ Decorators SHOULD NOT:
- Make direct HTTP calls (delegate to client)
- Swallow exceptions without logging
- Contain complex business logic
Common External Services
| Service | Purpose |
|---|---|
| Entitlement API | User resource accesss and permissions |
| Identity Mapper API | Account identity management |
| Dynamic Config API | Feature flags and configuration |
| Token API | data token generation and validation |
| Auth ID API | Business operations |
RestTemplate Configuration Bean
@Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000); // 5 second connect timeout
factory.setReadTimeout(10000); // 10 second read timeout
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(20);
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
factory.setHttpClient(httpClient);
return new RestTemplate(factory);
}
Error Handling Pattern
// In Decorator
public Response callApi(Request req) throws ApiException {
try {
return client.call(req);
} catch (HttpProxyCallException e) {
if (e.getHttpStatusCode() == 404) {
throw new NotFoundException("Resource not found");
} else if (e.getHttpStatusCode() >= 500) {
throw new InternalServerException("Downstream service error");
} else {
throw new ApiException("API call failed", e);
}
}
}
Related Layers
- Service Layer: Consumes decorators (not raw clients) for business logic
- Exception Layer: Domain exceptions thrown by decorators
- Config Layer: Provides URLs, timeouts, credentials, feature flags
Summary
Clients in this layer follow a resilient architecture using:
- ✅ Decorator pattern for separation of concerns
- ✅ Interface-driven design for testability
- ✅ Proper error handling and logging
- ✅ Configuration externalization
- ✅ Resilience patterns (timeouts, retries, circuit breakers)
- ✅ Connection pooling for performance
- ✅ Security best practices (HTTPS, no hardcoded credentials)
Keep clients pure (HTTP only), use decorators for cross-cutting concerns, and always implement resilience patterns.