From 8b960b27a382c1ecb90b1bebd7c6c72146cfa3dc Mon Sep 17 00:00:00 2001 From: Tarun Telang Date: Fri, 21 Mar 2025 15:22:54 +0530 Subject: [PATCH 01/11] Create index.adoc for chapter 11 initial few sections. --- chapter 11/index.adoc | 65 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 chapter 11/index.adoc diff --git a/chapter 11/index.adoc b/chapter 11/index.adoc new file mode 100644 index 00000000..c8b9f5f9 --- /dev/null +++ b/chapter 11/index.adoc @@ -0,0 +1,65 @@ += Chapter 11: MicroProfile Rest Client + +In microservices architecture, developers often face the cumbersome task of implementing boilerplate code to consume REST APIs - manually constructing HTTP requests, parsing responses, and handling errors. The MicroProfile Rest Client specification addresses this by leveraging Jakarta RESTful Web Services (formerly JAX-RS) annotations to create type-safe Rest client interfaces. Instead of writing low-level HTTP logic, developers define Java interfaces that mirror the target service’s endpoints. At runtime, MicroProfile Rest Client dynamically generates an implementation of these interfaces, automating HTTP communication while ensuring compile-time consistency between the client and server contracts. + +This chapter introduces the MicroProfile Rest Client, a type-safe framework for simplifying service-to-service communication. We will begin by defining REST client interfaces using Jakarta RESTful Web Services annotations (`@GET`, `@Path`) and configuring endpoints via MicroProfile Config, and implementing HTTP invocation. Next, we will explore handling HTTP communication, processing response, and error handling. By the end of this chapter, you will be able to replace hand-written HTTP boilerplate code with declarative, maintainable clients—while adhering to Jakarta EE and MicroProfile standards. + +== Topics to be covered: + +* Introduction to MicroProfile Rest Client +* Setting up Dependencies +* Defining a Rest Client Interface +* Parameter Configuration +* Requests and Response Handling +* Working with JSON Data formats +* Error Handling Strategies + +== Introduction to MicroProfile Rest Client + +The MicroProfile Rest Client specification simplifies RESTful service consumption in Java microservices by replacing error-prone manual HTTP handling with a type-safe, annotation-driven approach. Instead of writing boilerplate code, developers define Java interfaces that mirror the target service’s API. Using Jakarta RESTful Web Services annotations like @GET, and @Path, these interfaces declaratively map methods to HTTP operations (e.g., /users/{id} to getUser(id)). The framework then generates an implementation at runtime, automating communication while ensuring compile-time consistency between client and server contracts. Tight integration with MicroProfile Config and CDI allows seamless configuration and injection, making it ideal for building resilient, maintainable clients that align with modern microservices practices. + +==== Key Features of MicroProfile Rest Client + +The MicroProfile Rest Client simplifies RESTful service consumption in Java microservices with the following features: + +. *Type-Safe and Declarative APIs* - The MicroProfile Rest Client allows developers to define REST clients as Java interfaces using Jakarta RESTful Web Services annotations like `@GET`, `@POST`, `@PUT`, `@DELETE`, `@Path`, `@Consumes` and `@Produces`. This approach improves code clarity and ensures compile-time validation, reducing the possibility of runtime errors . +. *Integration with CDI (Context and Dependency Injection)* - This specification allows developers to seamlessly inject MicroProfilce Rest Client interfaces using `@Inject` and `@RestClient` into CDI-managed beans, promoting better dependency management and integration with other components. By leveraging CDI lifecycle management, the MicroProfile Rest Client can benefit from scope management (e.g. `@ApplicationScoped`), proxying, and automatic initialization. +. *Runtime Configurable with MicroProfile Config* - The behavior of MicroProfile Rest Client can be dynamically configured using MicroProfile Config. This allows properties like the base URL and other client settings to be adjusted without recompilation. The configuration can be provided through _microprofile-config.properties_ or environment variables, making the client highly adaptable to different environments. +. *Support for Asynchronous Execution* - For asynchronous execution, MicroProfile Rest Client can return `CompletionStage`, allowing non-blocking requests. This significantly improves performance & scalability in high-concurrency environments. +. *Automatic Handling of Redirect Responses* - MicroProfile Rest Client can automatically follow HTTP redirects, simplifying client implementation when working with services that return `3xx` responses. +. *Secure Socket Layer (SSL) and Security Configuration* - Supports SSL/TLS configuration, including certificates and trust stores, ensuring secure communication between microservices. +. *Propagation of Headers and Cookies* - Enables automatic propagation of HTTP headers, cookies and context (e.g., authentication tokens), facilitating session management across service calls. +. *Exception Handling and Custom Providers* - Allows custom exception mapping and response handling, giving developers control over error response based on specific conditions, improving fault tolerance and user experience. +. *Integration with MicroProfile Fault Tolerance* - This specification Supports resilience patterns like retries (`@Retry`), circuit breakers (`@CircuitBreaker`), and Bulkheads (`@Bulkhead`), ensuring stability in service-to-service communications. +. *Integration with MicroProfile Long Running Actions (LRA)* - MicroProfile Rest Client can coordinate distributed transactions using LRA annotations (e.g., `@LRA`), enabling compensation logic for long-running processes. This ensures consistency across services in complex workflows. +. *Portability and Standards Compliance*: This specification enables MicroProfile Rest Client to work across different MicroProfile-compatible runtimes, leveraging Jakarta EE standards (CDI, Jakarta RESTful Web Services, JSON Binding, JSON Processing). + +== Setting up Dependency for MicroProfile Rest Client + +To use MicroProfile Rest Client 3.1 in your project, you need to include the necessary dependencies in your build configuration. Below are configurations for Maven and Gradle: + +=== Maven Configuration +For Maven-based projects, add the following dependency to your pom.xml file: + +[source, xml] +---- + + org.eclipse.microprofile.rest.client + microprofile-rest-client-api + 3.1 + +---- + +=== Gradle Configuration + +For Gradle-based projects, add the following dependency to your build.gradle file: + +[source, xml] +---- +dependencies { + Implementation 'org.eclipse.microprofile.rest.client:microprofile-rest-client-api:3.1' + compileOnly 'org.eclipse.microprofile:microprofile:6.1' +} +---- + +> Tip: The MicroProfile Rest Client is an Eclipse Foundation project. For more details and updates on the project, visit the official repository: MicroProfile Rest Client on GitHub. From 88c762c803d265c0d455e20fb116ab81feeaadfa Mon Sep 17 00:00:00 2001 From: Tarun Telang Date: Fri, 21 Mar 2025 15:29:28 +0530 Subject: [PATCH 02/11] Update index.adoc --- chapter 11/index.adoc | 61 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/chapter 11/index.adoc b/chapter 11/index.adoc index c8b9f5f9..4883c7f2 100644 --- a/chapter 11/index.adoc +++ b/chapter 11/index.adoc @@ -63,3 +63,64 @@ dependencies { ---- > Tip: The MicroProfile Rest Client is an Eclipse Foundation project. For more details and updates on the project, visit the official repository: MicroProfile Rest Client on GitHub. + +== Creating MicroProfile Rest Client Interface + +To create a MicroProfile Rest Client interface, you need to define a Java interface and annotate it with annotations to map it to a RESTful service. + +=== The `@RegisterRestClient` Annotation + +To use the MicroProfile Rest Client, annotate your client interface with `@RegisterRestClient`. This annotation registers the interface as a Rest client within MicroProfile runtime and enables it as a CDI bean, allowing it to be injected into other components. + +Example: + +[source, java] +---- +package io.microprofile.tutorial.inventory.client; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +import io.microprofile.tutorial.inventory.dto.Product; + +@RegisterRestClient(configKey = "product-service") +@Path("/products") +public interface ProductServiceClient extends AutoCloseable { + + @GET + @Path("/{id}") + Product getProductById(@PathParam("id") Long id); +} +---- + +Explanation: +In the above code, we define a `ProductServiceClient` within the package `io.microprofile.tutorial.inventory.client`. The interface serves as a Rest client for interaction with a remote product service. It extends `AutoCloseable` interface, allowing the client to be closed when no longer needed, improving resource management. + +. `@RegisterRestClient` - declares the `ProductServiceClient` interface as a MicroProfile Rest Client, enabling it to be injected into other CDI-managed components. + +. The attribute `configKey = "product-service"` enables configuration via MicroProfile Config (using for e.g. _microprofile-config.properties_ or environment variables). + +. `@Path(/products)` - specifies the base URI of the RESTful service. + +. `@Path("/{id}")` – define a dynamic parameter `{id} `, which will be replaced at runtime with actual values. + +. `@PathParam("id")` - binds the method parameter `id` to the `{id}` path variable in the URL. + +. `@GET` - indicates that this method handles HTTP GET requests. + +. Return Type (`Product`) - The method returns a `Product` DTO (Data Transfer Object), which represents the retrieved product data. + +==== Configuration via MicroProfile Config: + +To configure the URI using MicroProfile Config, you need to add a config file named src/main/webapp/META-INF/microprofile-config.properties in your project. This file contains the configuration key and value pairs. In this example, we’re configuring the base URI to http://localhost:8080/api/products. We can configure other client properties, such as followRedirects. The followRedirects property specifies whether the client should automatically follow HTTP redirects (3xx status codes) when making RESTful web service calls. + +[source] +---- +product-service/mp-rest/url=http://localhost:8080/api/products +product-service/mp-rest/followRedirects=true. +---- + + From 4a96ad43d31eb6a59662087a62c022a6342e4418 Mon Sep 17 00:00:00 2001 From: Tarun Telang Date: Fri, 21 Mar 2025 15:46:52 +0530 Subject: [PATCH 03/11] Update index.adoc of chapter 11 chapter 11: MicroProfile Rest Client --- chapter 11/index.adoc | 273 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) diff --git a/chapter 11/index.adoc b/chapter 11/index.adoc index 4883c7f2..24c53241 100644 --- a/chapter 11/index.adoc +++ b/chapter 11/index.adoc @@ -123,4 +123,277 @@ product-service/mp-rest/url=http://localhost:8080/api/products product-service/mp-rest/followRedirects=true. ---- +== Parameter Configurations + +In MicroProfile Rest Client, you can dynamically configure headers, query parameters, and path parameters dynamically using Jakarta RESTful Web Services annotations. These annotations bind method parameters to different parts of the HTTP request, enabling flexible and dynamic RESTful client interfaces that can efficiently interact with various endpoints. + +*Supported Parameter Annotations* + +. `@PathParam` – Binds a method parameter to a path variable in the URL. + +. `@QueryParam` – Maps a method parameter to a query string parameter in the request URL. + +. `@HeaderParam` – Attaches a method parameter to an HTTP request header. + +These annotations eliminate manual string concatenation, making REST client calls type-safe and maintainable. + +=== Using Path Parameters (`@PathParam`) + +Path parameters are used to insert dynamic values directly into the URL path. + +[source, java] +---- +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@RegisterRestClient +@Path("/products") +public interface ProductServiceClient { + + @GET + @Path("/{id}") + Product getProductById(@PathParam("id") Long id); +} +---- + +Example +[source, java] +---- +productServiceClient.getProductById(1L); +---- + +Resulting HTTP Request +[source, http] +---- +GET /products/1 +---- + +==== Why Use @PathParam? + +. Ensures URL structure consistency by enforcing path variables +. Prevents hardcoding URLs, making the code cleaner and maintainable. + +=== Using Query Parameters (`@QueryParam`) + +Query parameters are typically used for filtering, pagination, or optional parameters in the request URL. + +Example: + +[source, java] +---- +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@RegisterRestClient +@Path("/products") +public interface ProductServiceClient { + + @GET + List getProductsByCategory(@QueryParam("category") String category); +} +---- + +Example Call: + +[source, java] +---- +productServiceClient.getProductsByCategory("electronics"); +---- + +Resulting HTTP Request: +[source, http] +---- +GET /products?category=electronics +---- + +==== Why Use @QueryParam? +. Useful for filtering results (?category=electronics). +. Ideal for pagination (?page=2&size=20). +. Allows sending optional parameters without modifying the URL structure. + +=== Using Header Parameters (@HeaderParam) + +Header parameters are typically used for authentication, authorization, and metadata transmission between client and server. + +Example: + +[source, java] +---- +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.Path; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@RegisterRestClient +@Path("/orders") +public interface OrderServiceClient { + + @GET + List getOrders(@HeaderParam("Authorization") String authToken); +} +---- + +Example Call: + +[source, java] +---- +orderServiceClient.getOrders("Bearer my-secret-token"); +---- + +Resulting HTTP Request: + +[source] +---- +GET /orders +Authorization: Bearer my-secret-token +---- + +==== Why Use @HeaderParam? +. Used for passing authentication tokens (Authorization: Bearer token). +. Helps with custom metadata exchange (e.g., X-Correlation-ID: 12345). +. Avoids exposing sensitive data in URLs (e.g., API keys). + +== Handling Requests and Responses + +In MicroProfile Rest Client, handling requests and responses involves defining methods in your interface that map to RESTful service endpoints. This ensures that: + +. HTTP requests are automatically constructed based on method definitions. +. Responses are efficiently deserialized into Java objects (DTOs) or processed manually using `Response`. + +By using Jakarta RESTful Web Services annotations, you can define GET, POST, PUT, and DELETE operations while MicroProfile handles serialization, deserialization, and request execution at runtime. + +== Handling JSON Data formats + +By default, MicroProfile Rest Client supports JSON format without requiring additional configurations. Serialization and deserialization of request and response bodies are automatically handled using JSON-B (Jakarta JSON Binding) or JSON-P (Jakarta JSON Processing). + +Developers can directly use Java objects as request bodies or response entities, eliminating the need for manual parsing. + +Example: + +[source, java] +---- +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.Consumes; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@RegisterRestClient +@Path("/products") +@Produces("application/json") +@Consumes("application/json") +public interface ProductServiceClient { + + @GET + @Path("/{id}") + Product getProductById(@PathParam("id") Long id); +} +---- + +*Explanation* + +. The `@Produces("application/json")` annotation specifies that the client expects JSON responses. This determines the value of the `Accept` header in HTTP requests. + +. The `@Consumes("application/json")` annotation specifies that the client sends JSON requests. This determines the value of the `Content-Type` header of the request. + +. By default the media type `"application/json"` is used if `@Produces` and `@Consumes` are not explicitly set. + +. MicroProfile Rest Client automatically serializes Java objects to JSON and deserializes responses into Product DTO (Data Transfer Object) Java object. + +=== Error Handling + +Effective handling of errors is crucial while consuming remote RESTful services. MicroProfile Rest Client provides a structured approach to error handling by mapping HTTP responses to exceptions using the `ResponseExceptionMapper` interface. + +This mechanism allows developers to: + +. Convert specific HTTP response codes into custom exceptions. +. Customize exception handling behavior at runtime. +. Automatically throw mapped exceptions in client invocations. + +==== Using RequestExceptionMapper interface + +The `ResponseExceptionMapper` interface allows mapping an HTTP Response object to a `Throwable` (custom exception). This improves error handling by ensuring meaningful exceptions are thrown instead of manually checking response codes. + +*How it Works* + +. *Scanning and Prioritizing Exception Mappers*: When a client method is invoked, the runtime scans all registered `ResponseExceptionMapper` implementations. Mappers are then sorted in ascending order of priority, determined by the `@Priority` annotation. The mapper with the lowest numeric priority value is checked first. + +. * Handling Responses: The `handles(int status, MultivaluedMap headers)` method determines whether a mapper should handle a given response. By default, it handles responses with status code 400 or higher, but we can override this behavior. + +. *Converting the Response to an Exception*: The `toThrowable(Response response)` method converts a response into a `Throwable` (exception). Checked exceptions are only thrown if the client method declares that it throws that type of exception of its superclass. Unchecked exceptions (RuntimeException) are always thrown. + +Example: + +[source, java] +---- +package io.microprofile.tutorial.inventory.client; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; +import org.eclipse.microprofile.rest.client.annotation.RegisterProvider; + +@RegisterRestClient(configKey = "product-service") +@RegisterProvider(ProductServiceResponseExceptionMapper.class) +@Path("/products") +public interface ProductServiceClient extends AutoCloseable { + + @GET + @Path("/{id}") + Response getProductById(@PathParam("id") Long id); +} +---- + +Explanation: + +. The REST client interface defines an endpoint for retrieving products. +. The `@RegisterProvider` annotation registers `ProductServiceResponseExceptionMapper`, ensuring custom exception handling. + +And below is the corresponding `ResponseExceptionMapper`: + +[source, java] +---- +package io.microprofile.tutorial.inventory.client; + +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper; +import io.microprofile.tutorial.inventory.dto.ProductNotFoundException; + +public class ProductServiceResponseExceptionMapper implements ResponseExceptionMapper { + + @Override + public Throwable toThrowable(Response response) { + if (response.getStatus() == 404) { + return new ProductNotFoundException("Product not found"); + } + return new Exception("An unexpected error occurred"); + } +} +---- +*Explanation:* + +If the response status code is `404`, a `ProductNotFoundException` is thrown. Otherwise, a generic exception is returned. + +=== Conclusion + +The MicroProfile Rest Client provides a declarative, type-safe, and efficient way to interact with RESTful services in Java microservices. It eliminates the need for boilerplate code, allowing developers to focus on business logic rather than low-level HTTP handling. + +By seamlessly integrating with other MicroProfile specifications—such as Config, Fault Tolerance, and JWT Authentication—the MicroProfile Rest Client enhances configurability, resilience, and security in cloud-native applications. + +==== Key Takeaways: + +* Removes boilerplate HTTP code, making REST clients concise and readable. +* Automatically handles serialization and deserialization of JSON and XML data. +* Supports CDI injection, enabling better lifecycle management. +* Integrates with MicroProfile Fault Tolerance for retry policies and circuit breakers. +* Enhances security through header propagation and authentication support. + +With MicroProfile Rest Client, building reliable and maintainable microservices that communicate over REST becomes simpler, more flexible, and more powerful. + From 6f2d19a266999e8ecf12f8b2bcd392b08ee3e06e Mon Sep 17 00:00:00 2001 From: Tarun Telang Date: Tue, 1 Apr 2025 10:57:42 +0530 Subject: [PATCH 04/11] chapter 11/Update index.adoc: : Add section on RestClientBuilder usage in Chapter 11 - Introduced programmatic client creation using RestClientBuilder - Added InventoryService example calling ProductService with RestClientBuilder - Explained builder pattern usage and method chaining benefits - Clarified when to prefer programmatic client creation over CDI - Included summary and key takeaways on MicroProfile Rest Client advantages --- chapter 11/index.adoc | 77 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 9 deletions(-) diff --git a/chapter 11/index.adoc b/chapter 11/index.adoc index 24c53241..94101d07 100644 --- a/chapter 11/index.adoc +++ b/chapter 11/index.adoc @@ -380,20 +380,79 @@ public class ProductServiceResponseExceptionMapper implements ResponseExceptionM If the response status code is `404`, a `ProductNotFoundException` is thrown. Otherwise, a generic exception is returned. +=== Using the `RestClientBuilder` Class + +While *CDI-based injection* is commonly used for REST clients in MicroProfile, programmatic creation using the `RestClientBuilder` class is beneficial when CDI is unavailable or when dynamic client instantiation is required. This builder provides a *fluent API* for configuring and constructing REST client proxies without relying on constructors that require numerous arguments. + +Using `RestClientBuilder` simplifies object creation, improves code readability, and supports *method chaining*, where each configuration method returns the builder instance itself. + +==== Example: Inventory Service Calls Product Service + +In the MicroProfile Ecommerce Store, the `InventoryService` must verify whether a product exists before checking or updating inventory. This interaction can be handled by calling the `ProductService` using a REST client interface. + +[source,java] +---- +package io.microprofile.tutorial.store.inventory.service; + +import io.microprofile.tutorial.store.inventory.client.ProductServiceClient; +import io.microprofile.tutorial.store.product.entity.Product; +import org.eclipse.microprofile.rest.client.RestClientBuilder; + +import java.net.URI; +import java.util.concurrent.TimeUnit; + +public class InventoryService { + + public boolean isProductAvailable(Long productId) { + try { + URI productApiUri = new URI("http://localhost:8080/api"); + + ProductServiceClient productClient = RestClientBuilder.newBuilder() + .baseUri(productApiUri) + .connectTimeout(3, TimeUnit.SECONDS) + .readTimeout(5, TimeUnit.SECONDS) + .build(ProductServiceClient.class); + + Product product = productClient.getProductById(productId); + + return product != null; + } catch (Exception e) { + // Log exception (omitted for brevity) + return false; + } + } +} +---- + +==== Explanation + +- The `isProductAvailable()` method accepts a product ID and returns `true` if the product exists in the catalog. +- A `URI` object is created pointing to the base path of the ProductService API. +- A `ProductServiceClient` instance is created using the builder pattern: + * `newBuilder()` initializes the client builder. + * `baseUri()` sets the root endpoint of the target service. + * `connectTimeout()` and `readTimeout()` define connection and read timeouts respectively. + * `build()` finalizes and returns the configured client proxy. +- If a `Product` object is successfully returned, `true` is returned. +- Any exceptions are caught and handled appropriately, returning `false` in case of failure. + +This approach is especially useful for *utility services*, *batch jobs*, or environments where REST client configuration must be *dynamic or conditional*. + === Conclusion -The MicroProfile Rest Client provides a declarative, type-safe, and efficient way to interact with RESTful services in Java microservices. It eliminates the need for boilerplate code, allowing developers to focus on business logic rather than low-level HTTP handling. +The *MicroProfile Rest Client* provides a declarative, type-safe, and efficient mechanism to interact with RESTful services in Java microservices. It reduces boilerplate code and lets developers focus on core business logic, while still offering fine-grained control through features like `RestClientBuilder`. + +By integrating seamlessly with other MicroProfile specifications—such as *Config*, *Fault Tolerance*, and *JWT Authentication*—the Rest Client helps enhance the *security*, *resilience*, and *maintainability* of cloud-native applications. -By seamlessly integrating with other MicroProfile specifications—such as Config, Fault Tolerance, and JWT Authentication—the MicroProfile Rest Client enhances configurability, resilience, and security in cloud-native applications. +==== Key Takeaways -==== Key Takeaways: +- Removes boilerplate HTTP code, improving clarity and maintainability. +- Automatically handles JSON serialization and deserialization. +- Supports *CDI injection* for managed client lifecycles. +- Integrates with *Fault Tolerance* for retries, timeouts, and circuit breakers. +- Enhances *security* through header propagation and authentication mechanisms. -* Removes boilerplate HTTP code, making REST clients concise and readable. -* Automatically handles serialization and deserialization of JSON and XML data. -* Supports CDI injection, enabling better lifecycle management. -* Integrates with MicroProfile Fault Tolerance for retry policies and circuit breakers. -* Enhances security through header propagation and authentication support. +With the MicroProfile Rest Client, building robust and maintainable microservices that communicate over REST becomes *simpler*, *more flexible*, and *more powerful*. -With MicroProfile Rest Client, building reliable and maintainable microservices that communicate over REST becomes simpler, more flexible, and more powerful. From 35f9f9db51cf5431b8aef8ea30b24341e5168fd0 Mon Sep 17 00:00:00 2001 From: Tarun Telang Date: Tue, 1 Apr 2025 11:00:09 +0530 Subject: [PATCH 05/11] Update index.adoc Adding a closing statement to the MicroProfile tutorial. --- chapter 11/index.adoc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/chapter 11/index.adoc b/chapter 11/index.adoc index 94101d07..f9bdc1fc 100644 --- a/chapter 11/index.adoc +++ b/chapter 11/index.adoc @@ -452,7 +452,4 @@ By integrating seamlessly with other MicroProfile specifications—such as *Conf - Integrates with *Fault Tolerance* for retries, timeouts, and circuit breakers. - Enhances *security* through header propagation and authentication mechanisms. -With the MicroProfile Rest Client, building robust and maintainable microservices that communicate over REST becomes *simpler*, *more flexible*, and *more powerful*. - - - +With the MicroProfile Rest Client, building robust and maintainable microservices that communicate over REST becomes *simpler*, *more flexible*, and *more powerful*. This concludes the MicroProfile tutorial. You are now equipped with the foundational knowledge to build robust, cloud-native microservices using the MicroProfile specification. Happy coding!! From e94244a2f7321bcf6b1ed511638d47ef8d76026d Mon Sep 17 00:00:00 2001 From: Tarun Telang Date: Sun, 27 Apr 2025 10:28:26 +0530 Subject: [PATCH 06/11] Update index.adoc Fix for https://github.com/microprofile/microprofile-tutorial/pull/26#discussion_r2038225806 --- chapter 11/index.adoc | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/chapter 11/index.adoc b/chapter 11/index.adoc index f9bdc1fc..23b2ff16 100644 --- a/chapter 11/index.adoc +++ b/chapter 11/index.adoc @@ -1,8 +1,10 @@ = Chapter 11: MicroProfile Rest Client +:rest-client-spec-name: MicroProfile Rest Client +:rest-client-spec-version: 3.1 In microservices architecture, developers often face the cumbersome task of implementing boilerplate code to consume REST APIs - manually constructing HTTP requests, parsing responses, and handling errors. The MicroProfile Rest Client specification addresses this by leveraging Jakarta RESTful Web Services (formerly JAX-RS) annotations to create type-safe Rest client interfaces. Instead of writing low-level HTTP logic, developers define Java interfaces that mirror the target service’s endpoints. At runtime, MicroProfile Rest Client dynamically generates an implementation of these interfaces, automating HTTP communication while ensuring compile-time consistency between the client and server contracts. -This chapter introduces the MicroProfile Rest Client, a type-safe framework for simplifying service-to-service communication. We will begin by defining REST client interfaces using Jakarta RESTful Web Services annotations (`@GET`, `@Path`) and configuring endpoints via MicroProfile Config, and implementing HTTP invocation. Next, we will explore handling HTTP communication, processing response, and error handling. By the end of this chapter, you will be able to replace hand-written HTTP boilerplate code with declarative, maintainable clients—while adhering to Jakarta EE and MicroProfile standards. +This chapter introduces the MicroProfile Rest Client, a type-safe framework for simplifying service-to-service communication. We will begin by defining REST client interfaces using Jakarta RESTful Web Services annotations (`@GET`, `@Path`), configuring endpoints via MicroProfile Config, and implementing HTTP invocation. Next, we will explore handling HTTP communication, processing responses, and error handling. By the end of this chapter, you will be able to replace hand-written HTTP boilerplate code with declarative, maintainable clients while adhering to Jakarta EE and MicroProfile standards. == Topics to be covered: @@ -16,14 +18,14 @@ This chapter introduces the MicroProfile Rest Client, a type-safe framework for == Introduction to MicroProfile Rest Client -The MicroProfile Rest Client specification simplifies RESTful service consumption in Java microservices by replacing error-prone manual HTTP handling with a type-safe, annotation-driven approach. Instead of writing boilerplate code, developers define Java interfaces that mirror the target service’s API. Using Jakarta RESTful Web Services annotations like @GET, and @Path, these interfaces declaratively map methods to HTTP operations (e.g., /users/{id} to getUser(id)). The framework then generates an implementation at runtime, automating communication while ensuring compile-time consistency between client and server contracts. Tight integration with MicroProfile Config and CDI allows seamless configuration and injection, making it ideal for building resilient, maintainable clients that align with modern microservices practices. +The MicroProfile Rest Client specification simplifies RESTful service consumption in Java microservices by replacing error-prone manual HTTP handling with a type-safe, annotation-driven approach. Instead of writing boilerplate code, developers define Java interfaces that mirror the target service’s API. Using Jakarta RESTful Web Services annotations like `@GET`, and `@Path`, these interfaces declaratively map methods to HTTP operations (e.g., `/users/{id}` to `getUser(id)`). The framework then generates an implementation at runtime, automating communication while ensuring compile-time consistency between client and server contracts. Tight integration with MicroProfile Config and CDI allows seamless configuration and injection, making it ideal for building resilient, maintainable clients that align with modern microservices practices. ==== Key Features of MicroProfile Rest Client -The MicroProfile Rest Client simplifies RESTful service consumption in Java microservices with the following features: +The MicroProfile Rest Client simplifies consuming RESTful services in Java microservices with the following key features: . *Type-Safe and Declarative APIs* - The MicroProfile Rest Client allows developers to define REST clients as Java interfaces using Jakarta RESTful Web Services annotations like `@GET`, `@POST`, `@PUT`, `@DELETE`, `@Path`, `@Consumes` and `@Produces`. This approach improves code clarity and ensures compile-time validation, reducing the possibility of runtime errors . -. *Integration with CDI (Context and Dependency Injection)* - This specification allows developers to seamlessly inject MicroProfilce Rest Client interfaces using `@Inject` and `@RestClient` into CDI-managed beans, promoting better dependency management and integration with other components. By leveraging CDI lifecycle management, the MicroProfile Rest Client can benefit from scope management (e.g. `@ApplicationScoped`), proxying, and automatic initialization. +. *Integration with CDI (Context and Dependency Injection)* - This specification allows developers to seamlessly inject MicroProfile Rest Client interfaces using `@Inject` and `@RestClient` into CDI-managed beans, promoting better dependency management and integration with other components. By leveraging CDI lifecycle management, the MicroProfile Rest Client can benefit from scope management (e.g., `@ApplicationScoped`), proxying, and automatic initialization. . *Runtime Configurable with MicroProfile Config* - The behavior of MicroProfile Rest Client can be dynamically configured using MicroProfile Config. This allows properties like the base URL and other client settings to be adjusted without recompilation. The configuration can be provided through _microprofile-config.properties_ or environment variables, making the client highly adaptable to different environments. . *Support for Asynchronous Execution* - For asynchronous execution, MicroProfile Rest Client can return `CompletionStage`, allowing non-blocking requests. This significantly improves performance & scalability in high-concurrency environments. . *Automatic Handling of Redirect Responses* - MicroProfile Rest Client can automatically follow HTTP redirects, simplifying client implementation when working with services that return `3xx` responses. @@ -125,7 +127,7 @@ product-service/mp-rest/followRedirects=true. == Parameter Configurations -In MicroProfile Rest Client, you can dynamically configure headers, query parameters, and path parameters dynamically using Jakarta RESTful Web Services annotations. These annotations bind method parameters to different parts of the HTTP request, enabling flexible and dynamic RESTful client interfaces that can efficiently interact with various endpoints. +In MicroProfile Rest Client, you can dynamically configure headers, query parameters, and path parameters using Jakarta RESTful Web Services annotations. These annotations bind method parameters to different parts of the HTTP request, enabling flexible and dynamic RESTful client interfaces that can efficiently interact with various endpoints. *Supported Parameter Annotations* @@ -264,7 +266,7 @@ In MicroProfile Rest Client, handling requests and responses involves defining m . HTTP requests are automatically constructed based on method definitions. . Responses are efficiently deserialized into Java objects (DTOs) or processed manually using `Response`. -By using Jakarta RESTful Web Services annotations, you can define GET, POST, PUT, and DELETE operations while MicroProfile handles serialization, deserialization, and request execution at runtime. +Using Jakarta RESTful Web Services annotations, you can define standard HTTP operations such as @GET, @POST, @PUT, and @DELETE. The framework also supports additional methods like @HEAD, @OPTIONS, and @PATCH, providing complete control over HTTP communication when needed. Meanwhile, MicroProfile automatically handles serialization, deserialization, and request execution at runtime. == Handling JSON Data formats @@ -306,7 +308,7 @@ public interface ProductServiceClient { === Error Handling -Effective handling of errors is crucial while consuming remote RESTful services. MicroProfile Rest Client provides a structured approach to error handling by mapping HTTP responses to exceptions using the `ResponseExceptionMapper` interface. +Effective error handling is crucial when consuming remote RESTful services. MicroProfile Rest Client provides a structured approach to error handling by mapping HTTP responses to exceptions using the `ResponseExceptionMapper` interface. This mechanism allows developers to: @@ -314,7 +316,7 @@ This mechanism allows developers to: . Customize exception handling behavior at runtime. . Automatically throw mapped exceptions in client invocations. -==== Using RequestExceptionMapper interface +==== Using `ResponseExceptionMapper` interface The `ResponseExceptionMapper` interface allows mapping an HTTP Response object to a `Throwable` (custom exception). This improves error handling by ensuring meaningful exceptions are thrown instead of manually checking response codes. @@ -324,7 +326,7 @@ The `ResponseExceptionMapper` interface allows mapping an HTTP Response object t . * Handling Responses: The `handles(int status, MultivaluedMap headers)` method determines whether a mapper should handle a given response. By default, it handles responses with status code 400 or higher, but we can override this behavior. -. *Converting the Response to an Exception*: The `toThrowable(Response response)` method converts a response into a `Throwable` (exception). Checked exceptions are only thrown if the client method declares that it throws that type of exception of its superclass. Unchecked exceptions (RuntimeException) are always thrown. +. *Converting the Response to an Exception*: The `toThrowable(Response response)` method converts a response into a `Throwable` (exception). Checked exceptions are only thrown if the client method declares that it throws that type of exception of its superclass. Unchecked exceptions (`RuntimeException`) are always thrown. Example: @@ -452,4 +454,4 @@ By integrating seamlessly with other MicroProfile specifications—such as *Conf - Integrates with *Fault Tolerance* for retries, timeouts, and circuit breakers. - Enhances *security* through header propagation and authentication mechanisms. -With the MicroProfile Rest Client, building robust and maintainable microservices that communicate over REST becomes *simpler*, *more flexible*, and *more powerful*. This concludes the MicroProfile tutorial. You are now equipped with the foundational knowledge to build robust, cloud-native microservices using the MicroProfile specification. Happy coding!! +With MicroProfile Rest Client, building robust and maintainable microservices that communicate over REST becomes *simpler*, *more flexible*, and *more powerful*. This concludes the MicroProfile tutorial. You are now equipped with the foundational knowledge to build robust, cloud-native microservices using the MicroProfile specification. Thank you for following along, and happy coding! From 7f2e90638af7660a39196caab01b7aff144747d2 Mon Sep 17 00:00:00 2001 From: Tarun Telang Date: Sun, 27 Apr 2025 10:28:59 +0530 Subject: [PATCH 07/11] Update chapter 11/index.adoc Co-authored-by: Radoslav Husar --- chapter 11/index.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapter 11/index.adoc b/chapter 11/index.adoc index 23b2ff16..7de34081 100644 --- a/chapter 11/index.adoc +++ b/chapter 11/index.adoc @@ -324,7 +324,7 @@ The `ResponseExceptionMapper` interface allows mapping an HTTP Response object t . *Scanning and Prioritizing Exception Mappers*: When a client method is invoked, the runtime scans all registered `ResponseExceptionMapper` implementations. Mappers are then sorted in ascending order of priority, determined by the `@Priority` annotation. The mapper with the lowest numeric priority value is checked first. -. * Handling Responses: The `handles(int status, MultivaluedMap headers)` method determines whether a mapper should handle a given response. By default, it handles responses with status code 400 or higher, but we can override this behavior. +. *Handling Responses*: The `handles(int status, MultivaluedMap headers)` method determines whether a mapper should handle a given response. By default, it handles responses with status code 400 or higher, but we can override this behavior. . *Converting the Response to an Exception*: The `toThrowable(Response response)` method converts a response into a `Throwable` (exception). Checked exceptions are only thrown if the client method declares that it throws that type of exception of its superclass. Unchecked exceptions (`RuntimeException`) are always thrown. From cd436951b6f7bd8e4b25834b6c9241dc9c8d32d5 Mon Sep 17 00:00:00 2001 From: Tarun Telang Date: Sun, 27 Apr 2025 16:03:48 +0530 Subject: [PATCH 08/11] Update index.adoc Fix for https://github.com/microprofile/microprofile-tutorial/pull/26#discussion_r2038187203 --- chapter 11/index.adoc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/chapter 11/index.adoc b/chapter 11/index.adoc index 7de34081..70a4f277 100644 --- a/chapter 11/index.adoc +++ b/chapter 11/index.adoc @@ -90,7 +90,7 @@ import io.microprofile.tutorial.inventory.dto.Product; @RegisterRestClient(configKey = "product-service") @Path("/products") -public interface ProductServiceClient extends AutoCloseable { +public interface ProductServiceClient { @GET @Path("/{id}") @@ -99,21 +99,23 @@ public interface ProductServiceClient extends AutoCloseable { ---- Explanation: -In the above code, we define a `ProductServiceClient` within the package `io.microprofile.tutorial.inventory.client`. The interface serves as a Rest client for interaction with a remote product service. It extends `AutoCloseable` interface, allowing the client to be closed when no longer needed, improving resource management. +In the above code, we define a `ProductServiceClient` within the package `io.microprofile.tutorial.inventory.client`. The interface serves as a Rest client for interaction with a remote product service. . `@RegisterRestClient` - declares the `ProductServiceClient` interface as a MicroProfile Rest Client, enabling it to be injected into other CDI-managed components. -. The attribute `configKey = "product-service"` enables configuration via MicroProfile Config (using for e.g. _microprofile-config.properties_ or environment variables). +. `configKey = "product-service"` - associates the client with a configuration key, allowing dynamic configuration via MicroProfile Config (e.g., using _microprofile-config.properties_ or environment variables). + +. `@Path(/products)` - specifies the base URI path segement for the RESTful service. -. `@Path(/products)` - specifies the base URI of the RESTful service. +. `@GET` - indicates that the `getProductById()` method handles HTTP GET requests. -. `@Path("/{id}")` – define a dynamic parameter `{id} `, which will be replaced at runtime with actual values. +. `@Path("/{id}")` – define a dynamic URI path parameter `{id}`, which will be replaced at runtime with the actual value provided. -. `@PathParam("id")` - binds the method parameter `id` to the `{id}` path variable in the URL. +. `@PathParam("id")` - binds the method parameter `id` to the `{id}` placeholder in the request URL. -. `@GET` - indicates that this method handles HTTP GET requests. +. Return Type (`Product`) - specifies that the method returns a `Product` Data Transfer Object (DTO), representing the retrieved product data. -. Return Type (`Product`) - The method returns a `Product` DTO (Data Transfer Object), which represents the retrieved product data. +> Note: In CDI environments, it is recommended not to extend AutoCloseable in REST client interfaces. The container manages the lifecycle of injected clients automatically, ensuring proper resource handling without requiring manual closure. ==== Configuration via MicroProfile Config: From cc36213fe49a38a25ec3ec3e7f0a9cf5ef97b6d8 Mon Sep 17 00:00:00 2001 From: Tarun Telang Date: Sun, 27 Apr 2025 16:20:55 +0530 Subject: [PATCH 09/11] Update index.adoc Fix for https://github.com/microprofile/microprofile-tutorial/pull/26#discussion_r2038205713 --- chapter 11/index.adoc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/chapter 11/index.adoc b/chapter 11/index.adoc index 70a4f277..ab18aea2 100644 --- a/chapter 11/index.adoc +++ b/chapter 11/index.adoc @@ -139,8 +139,6 @@ In MicroProfile Rest Client, you can dynamically configure headers, query parame . `@HeaderParam` – Attaches a method parameter to an HTTP request header. -These annotations eliminate manual string concatenation, making REST client calls type-safe and maintainable. - === Using Path Parameters (`@PathParam`) Path parameters are used to insert dynamic values directly into the URL path. @@ -261,6 +259,18 @@ Authorization: Bearer my-secret-token . Helps with custom metadata exchange (e.g., X-Correlation-ID: 12345). . Avoids exposing sensitive data in URLs (e.g., API keys). +=== Overview of Additional Annotations + +. `@CookieParam` - Binds a method parameter to the value of an HTTP cookie in the incoming request. + +. `@FormParam` — Maps a method parameter to a field in a submitted HTML form (`application/x-www-form-urlencoded` POST body). + +. `@MatrixParam` — Binds a method parameter to a matrix parameter embedded within the URL path segements (e.g., `/product;color=blue;size=large`). + +. `@BeanParam` — Aggregates multiple parameter annotations (path, query, header, etc.) into a single Java bean for cleaner method signature. + +> Tip: These annotations eliminate manual string concatenation, making REST client calls type-safe and maintainable. + == Handling Requests and Responses In MicroProfile Rest Client, handling requests and responses involves defining methods in your interface that map to RESTful service endpoints. This ensures that: From 1bdebc35e94778e88b0bd52ca63f2f0aa614cf56 Mon Sep 17 00:00:00 2001 From: Tarun Telang Date: Sun, 27 Apr 2025 16:31:06 +0530 Subject: [PATCH 10/11] Update index.adoc Fix for https://github.com/microprofile/microprofile-tutorial/pull/26#discussion_r2038258613 --- chapter 11/index.adoc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/chapter 11/index.adoc b/chapter 11/index.adoc index ab18aea2..68615545 100644 --- a/chapter 11/index.adoc +++ b/chapter 11/index.adoc @@ -418,18 +418,17 @@ import java.util.concurrent.TimeUnit; public class InventoryService { public boolean isProductAvailable(Long productId) { - try { - URI productApiUri = new URI("http://localhost:8080/api"); + URI productApiUri = URI.create("http://localhost:8080/api"); - ProductServiceClient productClient = RestClientBuilder.newBuilder() + try (ProductServiceClient productClient = RestClientBuilder.newBuilder() .baseUri(productApiUri) .connectTimeout(3, TimeUnit.SECONDS) .readTimeout(5, TimeUnit.SECONDS) - .build(ProductServiceClient.class); + .build(ProductServiceClient.class)) { Product product = productClient.getProductById(productId); - return product != null; + } catch (Exception e) { // Log exception (omitted for brevity) return false; @@ -441,20 +440,23 @@ public class InventoryService { ==== Explanation - The `isProductAvailable()` method accepts a product ID and returns `true` if the product exists in the catalog. -- A `URI` object is created pointing to the base path of the ProductService API. -- A `ProductServiceClient` instance is created using the builder pattern: +- A `URI` object is created pointing to the base path of the ProductService API using `URI.create()`. +- A `ProductServiceClient` instance is created using the builder pattern inside a `try-with-resource` block: * `newBuilder()` initializes the client builder. * `baseUri()` sets the root endpoint of the target service. * `connectTimeout()` and `readTimeout()` define connection and read timeouts respectively. * `build()` finalizes and returns the configured client proxy. +- Because `ProductServiceClient` extends `AutoCloseable`, the try-with-resources block ensures that the client is automatically closed after the operation, preventing resource leaks. - If a `Product` object is successfully returned, `true` is returned. - Any exceptions are caught and handled appropriately, returning `false` in case of failure. -This approach is especially useful for *utility services*, *batch jobs*, or environments where REST client configuration must be *dynamic or conditional*. +This approach is especially useful for *utility services*, *batch jobs*, or environments where REST client configuration must be *dynamic or conditional*, and manual client lifecycle management is necessary. + +> Tip: When building MicroProfile REST clients programmatically (using `RestClientBuilder`), ensure that your client interface extends `AutoCloseable` and uses try-with-resources to release resources automatically. === Conclusion -The *MicroProfile Rest Client* provides a declarative, type-safe, and efficient mechanism to interact with RESTful services in Java microservices. It reduces boilerplate code and lets developers focus on core business logic, while still offering fine-grained control through features like `RestClientBuilder`. +The MicroProfile Rest Client provides a declarative, type-safe, and efficient mechanism for interacting with RESTful services in Java microservices. It reduces boilerplate code and lets developers focus on core business logic while still offering fine-grained control through features like `RestClientBuilder`. By integrating seamlessly with other MicroProfile specifications—such as *Config*, *Fault Tolerance*, and *JWT Authentication*—the Rest Client helps enhance the *security*, *resilience*, and *maintainability* of cloud-native applications. From b2f8d9bd696712c5d55cb95f9e840b05ffda58c1 Mon Sep 17 00:00:00 2001 From: Tarun Telang Date: Sun, 27 Apr 2025 16:33:29 +0530 Subject: [PATCH 11/11] Update index.adoc Fix for https://github.com/microprofile/microprofile-tutorial/pull/26#discussion_r2038190797 --- chapter 11/index.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapter 11/index.adoc b/chapter 11/index.adoc index 68615545..7ca17ccc 100644 --- a/chapter 11/index.adoc +++ b/chapter 11/index.adoc @@ -124,7 +124,7 @@ To configure the URI using MicroProfile Config, you need to add a config file na [source] ---- product-service/mp-rest/url=http://localhost:8080/api/products -product-service/mp-rest/followRedirects=true. +product-service/mp-rest/followRedirects=true ---- == Parameter Configurations