In RESTful microservices, REST clients send requests to other services to retrieve or modify resources, and the services respond to these requests. 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. REST architecture is characterized by statelessness, meaning the service doesn’t need to know anything about the client’s 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.
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 provides a simple, easy-to-build template to access remote RESTful services. The template interface you build 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 saves you the time and trouble of having to write the boilerplate code, such as setting up a client class, connecting to the remote server, or invoking the correct URI with the correct parameters. MicroProfile Rest Client simplifies the client-side API by handling the communication between the client and service. You only need to define and annotate an interface that describes the actions that you need to perform on a REST resource. An implementation of this interface is automatically generated for you when CDI is used to inject your client into a dependent class.
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 invoked synchronously or asynchronously. If the return type is a
CompletionStage, the service is invoked asynchronously; all other return types are invoked synchronously. One advantage of asynchronous behavior is that multiple services can be invoked simultaneously, resulting in faster overall execution.
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’re sending requests to a RESTful API, it’s important to be selective with the requests you send and flexible with the responses you receive. In practical terms, 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 enable you to ignore unknown variables and define or filter which attributes to serialize.