Create simple REST API client using Jersey
In the current post, I will give code examples how to build REST API client using Jersey. The code shown in examples below is available in GitHub java-samples/wiremock repository.
REST API client
REST API client is needed when you want to consume given REST API, either for production usage or for testing this API. In the latter case, the client does not need to be very sophisticated since it is used just for testing the API with Java code. In the current post, I will show how to create REST API client for Persons functionality of Dropwizard Rest Stub described in Build a RESTful stub server with Dropwizard post.Jersey 2 and Jackson
Jersey is a framework which allows an easier building of RESTful services. It is one of the most used such frameworks nowadays. Jackson is JSON parser for Java. It is also one of the most used ones. The first step is to import libraries you are going to use:<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.25.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.25.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.7</version>
</dependency>
Not mandatory but it is good practice to create an interface for this client and then do implementations. The idea is you may have different implementations and switch between them.
import com.automationrhapsody.wiremock.model.Person;
import java.util.List;
public interface PersonRestClient {
List<Person> getAll();
Person get(int id);
String save(Person person);
String remove();
}
Now you can start with implementation. In given example constructor take the host which also includes port and scheme. Then it creates ClientConfig object with specific properties. The full list is shown in ClientProperties Javadoc. In the example, I set up timeouts only. Next is to create WebTarget object to query different API endpoints. It could not be simpler than that:
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.filter.LoggingFilter;
public class JerseyPersonRestClient implements PersonRestClient {
private final WebTarget webTarget;
public JerseyPersonRestClient(String host) {
ClientConfig clientConfig = new ClientConfig()
.property(ClientProperties.READ_TIMEOUT, 30000)
.property(ClientProperties.CONNECT_TIMEOUT, 5000);
webTarget = ClientBuilder
.newClient(clientConfig)
.register(new LoggingFilter())
.target(host);
}
}
Once WebTarget is instantiated it will be used to query all the endpoints. I will show an implementation of one GET and one POST endpoints consumption:
@Override
public List<Person> getAll() {
Person[] persons = webTarget
.path(ENDPOINT_GET_ALL)
.request()
.get()
.readEntity(Person[].class);
return Arrays.stream(persons).collect(Collectors.toList());
}
@Override
public String save(Person person) {
if (person == null) {
throw new RuntimeException("Person entity should not be null");
}
return webTarget
.path(ENDPOINT_SAVE)
.request()
.post(Entity.json(person))
.readEntity(String.class);
}
The full code can be seen in GitHub repo: JerseyPersonRestClient full code.
jersey-media-json-jackson
This is the bonding between Jersey and Jackson. It should be used otherwise Jersey's readEntity(Class var1) method throws:Exception in thread “main” org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=application/json, type=class …
or
Exception in thread “main” org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=application/json, type=class …
Client builder
In the code, there is a class called PersonRestClientBuilder. In the current case it does not do many things, but in reality, it might turn out that a lot of configurations or input is provided to build a REST API client instance. This is where such builder becomes very useful:public class PersonRestClientBuilder {
private String host;
public PersonRestClientBuilder setHost(String host) {
this.host = host;
return this;
}
public PersonRestClient build() {
return new JerseyPersonRestClient(host);
}
}