REST clients
In RESTful microservices, REST clients send requests to other services to retrieve or modify resources, and the services respond to these requests. MicroProfile Rest Client provides a simple template to access remote RESTful services.
REST architecture is characterized by statelessness, meaning that the service doesn’t need to know anything about the client state, and vice versa. All the information that a service needs to respond to any request from a REST client is included in the request itself. For example, a music streaming service might implement a REST client to request the name of a song from a RESTful service that provides lists of artists and their songs. The following diagram shows the basic workflow of microservices architecture. A user sends requests to a REST client, which parcels these requests out to different microservices. The REST client then receives the responses, and bundles the data back to the user. Along the way, the data is serialized for transmission into JSON, a common byte string format, by using the JSON-B or JSON-P technologies.
MicroProfile Rest Client
The template interface that you build with MicroProfile REST Client maps to the remote service that you want to call. MicroProfile Rest Client automatically generates a client instance based on what is defined and annotated in the template interface. This template saves you the trouble of writing boilerplate code, such as setting up a client class, connecting to the remote server, or calling the correct URI and parameters. MicroProfile Rest Client simplifies the client-side API by handling the communication between the client and service. You need to define and annotate only an interface that describes the actions to perform on a REST resource. An implementation of this interface is automatically generated when CDI is used to inject your client into a dependent class.
You can use MicroProfile REST Client with Open Liberty by enabling the MicroProfile Rest Client feature in your server.xml
file. For more information, see Consuming RESTful services with template interfaces.
If you update your server from an earlier version of the MicroProfile REST Client to version 3.0, changes in API behavior might require you to update your application code. For more information, see Differences between MicroProfile REST Client 3.0 and 2.0.
Synchronous and asynchronous REST clients
REST clients can be implemented either synchronously or asynchronously. A synchronous client constructs an HTTP structure, sends a request, and waits for a response. An asynchronous client constructs an HTTP structure, sends a request, and moves on. In this case, the client is notified when the response arrives and the original thread, or another thread, can then process the response. The return type of the interface method determines whether a RESTful service is called synchronously or asynchronously. In MicroProfile Rest Client 2.0 and earlier, if the method has a CompletionStage
return type, the service is called asynchronously and all other return types are called synchronously. In MicroProfile Rest Client 2.0 and later, a method with the Publisher
return type is also called asynchronously. One advantage of asynchronous behavior is that multiple services can be called simultaneously, which results in faster overall execution.
Consuming RESTful APIs
Since RESTful microservices are stateless, the requests that clients make to an API contain all the information a service needs to respond. Therefore, RESTful requests and responses can contain data beyond just what’s in the HTTP URI and body. Data can be sent and received in HTTP headers, cookies, query parameters, path parameters, response status code, and more.
When you send requests to a RESTful API, be selective with the requests you send and flexible with the responses you receive. Don’t validate your request against variables or attributes that you don’t need, and be prepared to accept unknown attributes as part of the response. Don’t issue an exception just because you receive an unknown variable. Instead, look for language mechanisms that can ignore unknown variables and define or filter which attributes to serialize.