- Overview
- Services
- Technology Stack
- Quick Start
- API Documentation
- MicroProfile Rest Client 4.0 Features
- Testing the Services
- Verifying MicroProfile Rest Client Examples
- Prerequisites
- Example 1: Basic REST Client with @RegisterRestClient
- Example 2: MicroProfile Config Integration
- Example 3: CDI Injection with @Inject and @RestClient
- Example 4: Parameter Annotations (@PathParam, @QueryParam)
- Example 5: ResponseExceptionMapper - Custom Error Handling
- Verifying beans.xml Configuration
- Additional Testing Scenarios
- Viewing OpenAPI Documentation
- Debugging Tips
- Example 6: Custom Filters and Interceptors
- Example 7: RestClientBuilder for Programmatic Client Creation
- Learning Objective
- Troubleshooting Common Issues
- Project Structure
- Key MicroProfile Features Demonstrated
This project demonstrates a microservices-based e-commerce application built with Jakarta EE and MicroProfile, running on Open Liberty runtime. The application is composed of multiple independent services that work together to provide a complete e-commerce solution.
The application is split into the following microservices:
| Service | Description |
|---|---|
User Service |
Manages user accounts, authentication, and profile information |
Inventory Service |
Tracks product inventory and stock levels |
Order Service |
Manages customer orders, order items, and order status |
Catalog Service |
Provides product information, categories, and search capabilities |
Shopping Cart Service |
Manages user shopping cart items and temporary product storage |
Shipment Service |
Handles shipping orders, tracking, and delivery status updates |
Payment Service |
Processes payments and manages payment methods and transactions. Demonstrates MicroProfile Rest Client 4.0 features including CDI injection, ResponseExceptionMapper, custom filters, and programmatic client creation. |
-
Jakarta EE 10.0: For enterprise Java standardization
-
MicroProfile 7.x: For cloud-native APIs
-
MicroProfile Rest Client 4.0: Type-safe REST service consumption
-
Open Liberty: Lightweight, flexible runtime for Java microservices
-
Maven: For project management and builds
-
Clone the repository:
git clone https://github.com/microprofile/microprofile-tutorial.git cd code/chapter11 -
Start each microservice individually:
cd inventory
mvn liberty:runThe service will be available at http://localhost:7050/inventory
cd catalog
mvn liberty:runThe service will be available at http://localhost:9050/catalog
You can also run all services together using Docker Compose:
# Make the script executable (if needed)
chmod +x run-all-services.sh
# Run the script to build and start all services
./run-all-services.shOr manually:
# Build all projects first
cd user && mvn clean package && cd ..
cd inventory && mvn clean package && cd ..
cd order && mvn clean package && cd ..
cd catalog && mvn clean package && cd ..
# Start all services
docker-compose up -dThis will start all services in Docker containers with the following endpoints:
-
User Service: http://localhost:6050/user
-
Inventory Service: http://localhost:7050/inventory
-
Order Service: http://localhost:8050/order
-
Catalog Service: http://localhost:9050/catalog
Each microservice provides its own OpenAPI documentation, available at:
-
User Service: http://localhost:6050/user/openapi
-
Inventory Service: http://localhost:7050/inventory/openapi
-
Order Service: http://localhost:8050/order/openapi
-
Catalog Service: http://localhost:9050/catalog/openapi
This application demonstrates the latest MicroProfile Rest Client 4.0 features:
The Inventory Service showcases the new baseUri(String) method that eliminates the need for URI.create():
// MicroProfile Rest Client 4.0 - Simplified approach
ProductServiceClient client = RestClientBuilder.newBuilder()
.baseUri("http://localhost:5050/catalog/api") // Direct String parameter
.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build(ProductServiceClient.class);This replaces the older pattern:
// Old approach (Rest Client 3.x)
URI catalogServiceUri = URI.create("http://localhost:5050/catalog/api");
ProductServiceClient client = RestClientBuilder.newBuilder()
.baseUri(catalogServiceUri) // Required URI object
.build(ProductServiceClient.class);The @RestClient qualifier is mandatory for CDI injection:
@Inject
@RestClient // Required qualifier
private ProductServiceClient productClient;REST client interfaces extend AutoCloseable for proper resource management:
@RegisterRestClient(configKey = "product-service")
@Path("/products")
public interface ProductServiceClient extends AutoCloseable {
// Client methods
}See the InventoryService class for complete working examples of these features.
# Get all users
curl -X GET http://localhost:6050/user/api/users
# Create a new user
curl -X POST http://localhost:6050/user/api/users \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe",
"email": "jane@example.com",
"passwordHash": "password123",
"address": "123 Main St",
"phoneNumber": "555-123-4567"
}'
# Get a user by ID
curl -X GET http://localhost:6050/user/api/users/1
# Update a user
curl -X PUT http://localhost:6050/user/api/users/1 \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Smith",
"email": "jane@example.com",
"passwordHash": "password123",
"address": "456 Oak Ave",
"phoneNumber": "555-123-4567"
}'
# Delete a user
curl -X DELETE http://localhost:6050/user/api/users/1# Get all inventory items
curl -X GET http://localhost:7050/inventory/api/inventories
# Create a new inventory item
curl -X POST http://localhost:7050/inventory/api/inventories \
-H "Content-Type: application/json" \
-d '{
"productId": 101,
"quantity": 25
}'
# Get inventory by ID
curl -X GET http://localhost:7050/inventory/api/inventories/1
# Get inventory by product ID
curl -X GET http://localhost:7050/inventory/api/inventories/product/101
# Update inventory
curl -X PUT http://localhost:7050/inventory/api/inventories/1 \
-H "Content-Type: application/json" \
-d '{
"productId": 101,
"quantity": 50
}'
# Update product quantity
curl -X PATCH http://localhost:7050/inventory/api/inventories/product/101/quantity/75
# Delete inventory
curl -X DELETE http://localhost:7050/inventory/api/inventories/1# Get all orders
curl -X GET http://localhost:8050/order/api/orders
# Create a new order
curl -X POST http://localhost:8050/order/api/orders \
-H "Content-Type: application/json" \
-d '{
"userId": 1,
"totalPrice": 149.98,
"status": "CREATED",
"orderItems": [
{
"productId": 101,
"quantity": 2,
"priceAtOrder": 49.99
},
{
"productId": 102,
"quantity": 1,
"priceAtOrder": 50.00
}
]
}'
# Get order by ID
curl -X GET http://localhost:8050/order/api/orders/1
# Update order status
curl -X PATCH http://localhost:8050/order/api/orders/1/status/PAID
# Get items for an order
curl -X GET http://localhost:8050/order/api/orders/1/items
# Delete order
curl -X DELETE http://localhost:8050/order/api/orders/1The Payment Service demonstrates comprehensive MicroProfile Rest Client 4.0 features. Follow these steps to verify each example.
Before testing the examples, ensure both services are running:
# Terminal 1 - Start the Catalog Service (provides product data)
cd catalog
mvn liberty:run
# Terminal 2 - Start the Payment Service (consumes catalog service)
cd payment
mvn liberty:runThe services will be available at:
-
Catalog Service: http://localhost:5050/catalog
-
Payment Service: http://localhost:9050/payment
This example demonstrates defining a MicroProfile Rest Client interface with @RegisterRestClient.
What to Verify:
-
ProductClientinterface is annotated with@RegisterRestClient(configKey = "catalog-service") -
The client uses Jakarta REST annotations (
@GET,@Path,@PathParam) -
Configuration is externalized in
microprofile-config.properties
Test the Client:
# Get all products via REST client
curl http://localhost:9050/payment/catalog/products
# Expected Response: JSON array of products
[
{
"id": 1,
"name": "Laptop",
"price": 999.99
},
...
]Files to Review:
-
src/main/java/io/microprofile/tutorial/store/payment/client/ProductClient.java -
src/main/resources/META-INF/microprofile-config.properties
This example shows externalized configuration for REST clients using MicroProfile Config.
What to Verify:
-
Configuration properties follow the pattern:
<configKey>/mp-rest/<property> -
Base URL, timeouts, and scope are configured
-
Properties can be overridden via environment variables
Configuration Properties:
# Base URL
catalog-service/mp-rest/url=http://localhost:5050/catalog/api
# Timeouts (in milliseconds)
catalog-service/mp-rest/connectTimeout=3000
catalog-service/mp-rest/readTimeout=5000
# CDI Scope
catalog-service/mp-rest/scope=jakarta.enterprise.context.ApplicationScoped
# Follow redirects
catalog-service/mp-rest/followRedirects=trueTest Configuration:
# Verify the client respects timeout settings
# (This will timeout if catalog service is slow)
time curl http://localhost:9050/payment/catalog/productsFiles to Review:
-
src/main/resources/META-INF/microprofile-config.properties
This example demonstrates dependency injection of REST clients using CDI.
What to Verify:
-
ProductClientis injected with@Injectand@RestClientqualifiers -
The
@RestClientqualifier is mandatory in MicroProfile Rest Client 4.0 -
Service layer (
ProductCatalogService) uses the injected client -
@ApplicationScopedbean lifecycle management
Test CDI Injection:
# Test service that uses injected REST client
curl http://localhost:9050/payment/catalog/products
# Get specific product (uses getProductById method)
curl http://localhost:9050/payment/catalog/products/1
# Expected Response:
{
"id": 1,
"name": "Laptop",
"price": 999.99
}Files to Review:
-
src/main/java/io/microprofile/tutorial/store/payment/service/ProductCatalogService.java -
src/main/webapp/WEB-INF/beans.xml(CDI configuration)
This example shows different parameter types in REST client methods.
What to Verify:
-
@PathParamfor path variables (e.g.,/products/{id}) -
@QueryParamfor query string parameters (e.g.,?price=99.99) -
Parameters are automatically encoded and passed to remote service
Test Path Parameters:
# Test @PathParam - Get product by ID
curl http://localhost:9050/payment/catalog/products/1
# Test with different IDs
curl http://localhost:9050/payment/catalog/products/2
curl http://localhost:9050/payment/catalog/products/3Test Query Parameters:
# Test @QueryParam - Validate product price
curl "http://localhost:9050/payment/catalog/products/1/validate-price?price=999.99"
# Expected Response (if price matches):
{
"productId": 1,
"expectedPrice": 999.99,
"valid": true,
"message": "Price matches"
}
# Test with wrong price
curl "http://localhost:9050/payment/catalog/products/1/validate-price?price=500.00"
# Expected Response (if price doesn't match):
{
"productId": 1,
"expectedPrice": 500.0,
"valid": false,
"message": "Price mismatch detected"
}Files to Review:
-
src/main/java/io/microprofile/tutorial/store/payment/client/ProductClient.java(method signatures) -
src/main/java/io/microprofile/tutorial/store/payment/resource/ProductCatalogResource.java(endpoint implementation)
This example demonstrates mapping HTTP error responses to custom exceptions.
What to Verify:
-
ProductServiceResponseExceptionMapperimplementsResponseExceptionMapper<Throwable> -
HTTP 404 responses map to
ProductNotFoundException(checked exception) -
HTTP 503 responses map to
ServiceUnavailableException(unchecked exception) -
Error messages are extracted from JSON response bodies
-
@Priorityannotation controls mapper ordering
Test Exception Mapping:
# Test successful request (no exception)
curl http://localhost:9050/payment/catalog/products/1/detailed
# Expected Response:
{
"productId": 1,
"product": {
"id": 1,
"name": "Laptop",
"price": 999.99
},
"note": "Product retrieved successfully - no exceptions thrown"
}
# Test 404 error (ProductNotFoundException)
curl http://localhost:9050/payment/catalog/products/999999/detailed
# Expected Response:
{
"productId": 999999,
"error": "Product not found",
"note": "ProductNotFoundException was caught and handled by the service layer"
}
# Test product availability (handles 404 gracefully)
curl http://localhost:9050/payment/catalog/products/999999/availability
# Expected Response:
{
"productId": 999999,
"available": false,
"message": "Product is not available"
}Verify Exception Types:
-
Checked Exception (ProductNotFoundException):
-
Must be declared in method signature:
throws ProductNotFoundException -
Only thrown if method declares it
-
Handled gracefully in service layer
-
-
Unchecked Exception (ServiceUnavailableException):
-
Extends
RuntimeException -
Always thrown regardless of method signature
-
Used for service availability errors
-
Test Service Unavailable Scenario:
# Stop the catalog service to simulate 503 error
# Then try to access products
curl http://localhost:9050/payment/catalog/products/1/detailed
# Expected Response (if catalog service is down):
{
"productId": 1,
"error": "Catalog service unavailable",
"statusCode": 503,
"message": "...",
"note": "ServiceUnavailableException (unchecked) was thrown by ResponseExceptionMapper"
}Files to Review:
-
src/main/java/io/microprofile/tutorial/store/payment/client/ProductServiceResponseExceptionMapper.java -
src/main/java/io/microprofile/tutorial/store/payment/exception/ProductNotFoundException.java -
src/main/java/io/microprofile/tutorial/store/payment/exception/ServiceUnavailableException.java -
src/main/java/io/microprofile/tutorial/store/payment/client/ProductClient.java(see@RegisterProvider)
The beans.xml file is required for CDI bean discovery and REST client registration.
What to Verify:
-
File location:
src/main/webapp/WEB-INF/beans.xml -
Bean discovery mode:
bean-discovery-mode="all" -
Version: Jakarta EE 10 (beans 4.0)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
version="4.0"
bean-discovery-mode="all">
</beans>Files to Review:
-
src/main/webapp/WEB-INF/beans.xml
# 1. Check if product is available
curl http://localhost:9050/payment/catalog/products/1/availability
# 2. Validate product price before payment
curl "http://localhost:9050/payment/catalog/products/1/validate-price?price=999.99"
# 3. Get product details for payment processing
curl http://localhost:9050/payment/catalog/products/1# Invalid product ID (404)
curl http://localhost:9050/payment/catalog/products/999999
# Missing query parameter (400)
curl http://localhost:9050/payment/catalog/products/1/validate-price
# Invalid price value (400)
curl "http://localhost:9050/payment/catalog/products/1/validate-price?price=-10"Access the OpenAPI documentation to see all available endpoints:
# Payment Service OpenAPI documentation
open http://localhost:9050/openapi/ui/
# Or view the OpenAPI JSON spec
curl http://localhost:9050/openapiEnable Detailed Logging:
Edit src/main/liberty/config/server.xml and add:
<logging traceSpecification="*=info:org.eclipse.microprofile.rest.client=all"/>Check Server Logs:
# View real-time logs
tail -f target/liberty/wlp/usr/servers/mpServer/logs/messages.log
# Search for REST client activity
grep "ProductClient" target/liberty/wlp/usr/servers/mpServer/logs/messages.logVerify Configuration Loading:
# Check if properties are loaded correctly
# Look for log messages about MicroProfile Config
grep "mp-rest" target/liberty/wlp/usr/servers/mpServer/logs/messages.logThis example demonstrates implementing custom filters for cross-cutting concerns like authentication, logging, and distributed tracing.
What to Verify:
-
ClientRequestFilterimplementations for request interception -
ClientResponseFilterimplementations for response logging -
Filter registration using
@RegisterProvider -
Filter execution order using
@Priority -
Cross-cutting concerns separated from business logic
Filters Implemented:
-
BearerTokenFilter (Priority 1000 - AUTHENTICATION)
-
Adds Authorization header with Bearer token
-
Reads token from MicroProfile Config
-
Runs first due to authentication priority
-
-
CorrelationIdFilter (Priority 100)
-
Adds X-Correlation-ID for distributed tracing
-
Generates or propagates correlation IDs
-
Adds unique X-Request-ID for each request
-
-
RequestLoggingFilter (Priority 300)
-
Logs complete outgoing request details
-
Masks sensitive headers (Authorization, API keys)
-
Runs after authentication and correlation filters
-
-
ResponseLoggingFilter (Priority 300)
-
Logs complete incoming response details
-
Includes status codes, headers, timing
-
Correlates responses with requests
-
Test Basic Filter Functionality:
# Get all products with filters (watch server logs)
curl http://localhost:9050/payment/catalog/filtered/products
# Expected in logs:
# 1. "Bearer token authentication added to request" (if token configured)
# 2. "Generated new Correlation ID: <uuid>"
# 3. "=== Outgoing REST Client Request ==="
# 4. "Method: GET"
# 5. "URI: http://localhost:5050/catalog/api/products"
# 6. "=== Incoming REST Client Response ==="
# 7. "Status: 200 OK"Test Filter Execution with Specific Product:
# Get specific product - observe filter chain execution
curl http://localhost:9050/payment/catalog/filtered/products/1
# Expected Response:
{
"product": {
"id": 1,
"name": "Laptop",
"price": 999.99
},
"method": "REST Client with Custom Filters",
"filterChain": "BearerToken → CorrelationId → RequestLogging → [HTTP] → ResponseLogging",
"note": "Check server logs for X-Correlation-ID and detailed request/response traces"
}Test Filters with Error Responses:
# Test 404 error - filters still execute and log the error
curl http://localhost:9050/payment/catalog/filtered/products/999999
# Expected in logs:
# - RequestLoggingFilter logs the outgoing request
# - ResponseLoggingFilter logs: "Status: 404 Not Found"
# - ResponseLoggingFilter logs: "Result: CLIENT ERROR (404)"
# - ProductNotFoundException is thrown after logging
# Check product availability (handles 404 gracefully)
curl http://localhost:9050/payment/catalog/filtered/products/999999/available
# Expected Response:
{
"productId": 999999,
"available": false,
"method": "REST Client with Custom Filters",
"note": "Product not found - ResponseLoggingFilter logged 404 before returning false"
}Compare Filtered vs Non-Filtered Clients:
# Side-by-side comparison endpoint
curl http://localhost:9050/payment/catalog/compare/1
# This endpoint calls BOTH clients:
# 1. Non-filtered client (minimal logging)
# 2. Filtered client (comprehensive logging)
# Compare the server logs to see the difference in observabilityExpected Log Output (Filtered Client):
INFO: Getting product with custom filters: 1
INFO: Bearer token authentication added to request
INFO: Generated new Correlation ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
INFO: === Outgoing REST Client Request ===
INFO: Method: GET
INFO: URI: http://localhost:5050/catalog/api/products/1
INFO: Request Headers:
INFO: Authorization: [REDACTED]
INFO: X-Correlation-ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
INFO: X-Request-ID: b2c3d4e5-f6a7-8901-bcde-f12345678901
INFO: ===================================
INFO: === Incoming REST Client Response ===
INFO: Request: GET http://localhost:5050/catalog/api/products/1
INFO: Status: 200 OK
INFO: Content-Type: application/json
INFO: X-Correlation-ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
INFO: Result: SUCCESS
INFO: ====================================
INFO: Successfully retrieved product with filters: LaptopConfigure Bearer Token (Optional):
Edit src/main/resources/META-INF/microprofile-config.properties:
# Uncomment and set your Bearer token
catalog-service.bearer.token=your-test-token-hereRestart the server and test again - you’ll see the Authorization header added.
Verify Filter Priority:
Filter execution order is determined by @Priority values (lower numbers execute first):
Request Flow:
1. BearerTokenFilter (Priority 1000 - AUTHENTICATION)
2. CorrelationIdFilter (Priority 100)
3. RequestLoggingFilter (Priority 300)
4. --- HTTP REQUEST SENT ---
5. --- HTTP RESPONSE RECEIVED ---
6. ResponseLoggingFilter (Priority 300)Files to Review:
-
[BearerTokenFilter.java](src/main/java/io/microprofile/tutorial/store/payment/filter/BearerTokenFilter.java) - Authentication filter
-
[CorrelationIdFilter.java](src/main/java/io/microprofile/tutorial/store/payment/filter/CorrelationIdFilter.java) - Distributed tracing
-
[RequestLoggingFilter.java](src/main/java/io/microprofile/tutorial/store/payment/filter/RequestLoggingFilter.java) - Request logging
-
[ResponseLoggingFilter.java](src/main/java/io/microprofile/tutorial/store/payment/filter/ResponseLoggingFilter.java) - Response logging
-
[ProductClientWithFilters.java](src/main/java/io/microprofile/tutorial/store/payment/client/ProductClientWithFilters.java) - Client with filters registered
Benefits of Using Filters:
# Test the comparison endpoint to see benefits
curl http://localhost:9050/payment/catalog/compare/1
# Response shows benefits:
{
"comparison": {
"noFilters": "Minimal logging - only business logic logs",
"withFilters": "Comprehensive logging - authentication, tracing, request/response details"
},
"filterBenefits": [
"Authentication without changing business code",
"Distributed tracing with correlation IDs",
"Complete request/response visibility",
"Easier debugging and monitoring",
"Cross-cutting concerns separated from business logic"
]
}Common Use Cases for Filters:
-
Authentication: Inject API keys, Bearer tokens, Basic Auth credentials
-
Tracing: Propagate correlation IDs, request IDs, span IDs across services
-
Logging: Debug requests/responses without modifying business logic
-
Headers: Add custom headers, propagate context from incoming requests
-
Monitoring: Collect metrics, measure latency, track error rates
-
Security: Sign requests, validate responses, enforce policies
Security Best Practices:
-
Never log sensitive data (passwords, tokens, PII) in production
-
Use [REDACTED] masks for sensitive headers in logs
-
Store tokens in configuration, not hardcoded
-
Use environment-specific configuration for different deployments
-
Implement proper error handling in filters
This example demonstrates creating REST clients programmatically without CDI injection.
What to Verify:
-
Creating clients with
RestClientBuilder.newBuilder() -
Using
baseUri(String)method (MicroProfile Rest Client 4.0) -
Try-with-resources pattern with
AutoCloseable -
Dynamic configuration from MicroProfile Config
-
Environment-specific client configuration
Test Basic RestClientBuilder:
# Check product availability with programmatic client
curl http://localhost:9050/payment/catalog/builder/products/1/check
# Expected Response:
{
"productId": 1,
"available": true,
"method": "RestClientBuilder (programmatic)",
"note": "Product found using programmatically created client"
}Test Dynamic Configuration:
# Get product with configuration loaded from microprofile-config.properties
curl http://localhost:9050/payment/catalog/builder/products/1/dynamic
# Expected Response:
{
"product": {
"id": 1,
"name": "Laptop",
"price": 999.99
},
"method": "RestClientBuilder with dynamic config",
"note": "Configuration loaded from microprofile-config.properties at runtime"
}Test Environment-Specific Configuration:
# Get product for development environment
curl http://localhost:9050/payment/catalog/builder/products/1/env/dev
# Get product for staging environment (will fail if service not available)
curl http://localhost:9050/payment/catalog/builder/products/1/env/staging
# Get product for production environment (will fail if service not available)
curl http://localhost:9050/payment/catalog/builder/products/1/env/prod
# Expected Response (dev):
{
"product": {
"id": 1,
"name": "Laptop",
"price": 999.99
},
"environment": "dev",
"method": "RestClientBuilder with environment-specific config",
"note": "Client configured for dev environment"
}Test Batch Processing:
# Check multiple products in batch
curl -X POST http://localhost:9050/payment/catalog/builder/products/batch-check \
-H "Content-Type: application/json" \
-d '{"productIds": [1, 2, 3, 999, 1000]}'
# Expected Response:
{
"totalChecked": 5,
"availableCount": 3,
"unavailableCount": 2,
"method": "RestClientBuilder (batch processing)",
"note": "Each product checked with a separate programmatically created client instance"
}When to Use RestClientBuilder:
-
CDI is unavailable or not desired
-
Client configuration must be determined dynamically at runtime
-
Creating multiple clients with different configurations
-
Utility methods or batch jobs
-
Testing environments where CDI injection is complex
Files to Review:
-
[ProductClientBuilderService.java](src/main/java/io/microprofile/tutorial/store/payment/service/ProductClientBuilderService.java) - Programmatic client creation examples
-
[ProductClient.java](src/main/java/io/microprofile/tutorial/store/payment/client/ProductClient.java) - Note
extends AutoCloseable
After completing these examples, you should understand:
-
How to define a REST client interface with
@RegisterRestClient -
How to configure REST clients using MicroProfile Config properties
-
How to inject REST clients with
@Injectand@RestClientin CDI beans -
How to use parameter annotations (
@PathParam,@QueryParam,@HeaderParam) -
How to implement
ResponseExceptionMapperfor custom error handling -
The difference between checked and unchecked exceptions in exception mappers
-
How to register exception mappers with
@RegisterProvider -
How to extract error messages from JSON response bodies
-
How CDI bean discovery works with
beans.xml -
How to test REST clients in a microservices environment
-
How to implement custom
ClientRequestFilterfor request interception -
How to implement custom
ClientResponseFilterfor response logging -
How to use
@Priorityto control filter execution order -
How to register filters using
@RegisterProviderannotation -
How to separate cross-cutting concerns (auth, logging, tracing) from business logic
-
How to create REST clients programmatically using
RestClientBuilder -
How to use the
baseUri(String)method in MicroProfile Rest Client 4.0 -
When to use
RestClientBuildervs CDI injection -
How to use try-with-resources with
AutoCloseableREST clients -
How to dynamically configure REST clients at runtime
Issue: "Unsatisfied dependencies for type ProductClient"
Solution: Ensure beans.xml exists in src/main/webapp/WEB-INF/ with bean-discovery-mode="all"
Issue: "Connection refused" errors
Solution: Verify the catalog service is running on port 5050:
curl http://localhost:5050/catalog/api/productsIssue: "Read timeout" errors
Solution: Increase timeout values in microprofile-config.properties:
catalog-service/mp-rest/readTimeout=10000Issue: Exceptions not being mapped correctly
Solution: Verify @RegisterProvider is present on the client interface and the mapper implements ResponseExceptionMapper<Throwable>
liberty-rest-app/
├── user/ # User management service
├── inventory/ # Inventory management service
├── order/ # Order management service
└── catalog/ # Product catalog serviceEach service follows a similar internal structure:
service/
├── src/
│ ├── main/
│ │ ├── java/ # Java source code
│ │ ├── liberty/ # Liberty server configuration
│ │ └── webapp/ # Web resources
│ └── test/ # Test code
└── pom.xml # Maven configuration