How to Create a Rest Client for Java

How do you create a REST client for Java?

This is an old question (2008) so there are many more options now than there were then:

  • Apache CXF has three different REST Client options
  • Jersey (mentioned above).
  • Spring RestTemplate superceded by Spring WebClient
  • Commons HTTP Client build your own for older Java projects.

UPDATES (projects still active in 2020):

  • Apache HTTP Components (4.2) Fluent adapter - Basic replacement for JDK, used by several other candidates in this list. Better than old Commons HTTP Client 3 and easier to use for building your own REST client. You'll have to use something like Jackson for JSON parsing support and you can use HTTP components URIBuilder to construct resource URIs similar to Jersey/JAX-RS Rest client. HTTP components also supports NIO but I doubt you will get better performance than BIO given the short requestnature of REST. Apache HttpComponents 5 has HTTP/2 support.
  • OkHttp - Basic replacement for JDK, similar to http components, used by several other candidates in this list. Supports newer HTTP protocols (SPDY and HTTP2). Works on Android. Unfortunately it does not offer a true reactor-loop based async option (see Ning and HTTP components above). However if you use the newer HTTP2 protocol this is less of a problem (assuming connection count is problem).
  • Ning Async-http-client - provides NIO support. Previously known as Async-http-client by Sonatype.
  • Feign wrapper for lower level http clients (okhttp, apache httpcomponents). Auto-creates clients based on interface stubs similar to some Jersey and CXF extensions. Strong spring integration.
  • Retrofit - wrapper for lower level http clients (okhttp). Auto-creates clients based on interface stubs similar to some Jersey and CXF extensions.
  • Volley wrapper for jdk http client, by google
  • google-http wrapper for jdk http client, or apache httpcomponents, by google
  • Unirest wrapper for jdk http client, by kong
  • Resteasy JakartaEE wrapper for jdk http client, by jboss, part of jboss framework
  • jcabi-http wrapper for apache httpcomponents, part of jcabi collection
  • restlet wrapper for apache httpcomponents, part of restlet framework
  • rest-assured wrapper with asserts for easy testing

A caveat on picking HTTP/REST clients. Make sure to check what your framework stack is using for an HTTP client, how it does threading, and ideally use the same client if it offers one. That is if your using something like Vert.x or Play you may want to try to use its backing client to participate in whatever bus or reactor loop the framework provides... otherwise be prepared for possibly interesting threading issues.

How to create REST client for external world REST services

Requesting an entity and mapping it to a Java class

Consider, for example, you are consuming a REST API which provides the following JSON when performing a GET request at http://example.com/api/people/1:

{
"name": "John Doe",
"age": 25
}

The above JSON can be mapped to a Java class, defined as following:

public class Person {

private String name;

private Integer age;

// Constructor, getters and setters omitted
}

Using the JAX-RS Client API, the JSON can be requested as following, mapping the requested entity to the Person class:

Client client = ClientBuilder.newClient();
Person person = client.target("http://example.com/api")
.path("people").path("1")
.request(MediaType.APPLICATION_JSON)
.get(Person.class);

String name = person.getName();
Integer age = person.getAge();

The JAX-RS Client API is part of the JAX-RS 2.0 specification and the reference implementation is Jersey.

To parse JSON, Jersey comes with a set of extension modules for multiple frameworks that provide support for JSON processing and/or JSON-to-Java binding. Jersey supports MOXy, JSON-P, Jackson and Jettison. For more details, have a look at the documentation.

Parsing the JSON manually

If, for some reason, you need to parse the requested entity manually, you can store the requested entity in a String:

Client client = ClientBuilder.newClient();
String json = client.target("http://example.com/api")
.path("people").path("1")
.request(MediaType.APPLICATION_JSON)
.get(String.class);

And then the requested entity can be manually parsed using, for example, Jackson:

ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(json);

String name = node.path("name").asText();
Integer age = node.path("age").asInt();

To parse the JSON manually, you also could consider Gson.

Alternatives

For alternatives on how to consume REST APIs with Java, have a look at this answer.

What can I use to create a REST client in Java?

I've had success using HttpClient from Jakarta Commons.

Also Java comes with URLConnection but you might want to look at this comparison with HttpClient.

Apache CXF does support REST clients (see here) but seems like overkill (CXF is a general 'services' framework and therefore complicated with support for CORBA, SOAP etc.)

How to develop a simple REST Client using Swagger codegen?

Yes. You can use swagger-codegen-maven-plugin to generate a REST client. But before that , you need to describe the REST API in YAML or JSON in OpenAPI Specification mainly because swagger-codegen-maven-plugin only can generate a REST client from a file written in this specification.

Other answers assume that you need to write the specification manually while my solution take a step further to automatically generating the specification from the REST controller source codes.

The latest OpenAPI version is 3.0 .But based on the package of your imported swagger annotation , you are using version 2.0 (or before). So my solution assume you are using OpenAPI 2.0.

Generating Open API Specification

First, you can use swagger-maven-plugin to generate an OpenAPI spec from the RestController source codes. It basically analyses the Swagger annotations annotated in the @RestController classes that specified in <locations> and dump the OpenAPI spec to /src/main/resources/swagger.json :

<plugin>
<groupId>com.github.kongchen</groupId>
<artifactId>swagger-maven-plugin</artifactId>
<version>3.1.5</version>
<configuration>
<apiSources>
<apiSource>
<springmvc>true</springmvc>
<locations>
<location>com.dgs.spring.springbootswagger.controller.EmployeeController</location>
<location>com.dgs.spring.springbootswagger.controller.FooController</location>
</locations>
<schemes>
<scheme>http</scheme>
</schemes>
<host>127.0.0.1:8080</host>
<basePath>/</basePath>
<info>
<title>My API</title>
<version>1.1.1</version>
</info>
<swaggerDirectory>${basedir}/src/main/resources/</swaggerDirectory>
</apiSource>
</apiSources>
</configuration>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>

Execute the followings maven command to start generation:

mvn clean compile

Generating Rest Client

After swagger.json is generated, you can copy and paste it to your client project (e.g. /src/main/resources/swagger.json) . We can then use swagger-codegen-maven-plugin to generate a HTTP client .

By default , it will generate the whole maven project which includes test cases and other documentation stuff. But what I want is just the HttpClient 's source codes without other things. After several trial and error , I settle down to the following configuration :

<plugin>
<groupId>io.swagger</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
<version>2.4.7</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${basedir}/src/main/resources/swagger.json</inputSpec>
<language>java</language>
<library>resttemplate</library>
<output>${project.basedir}/target/generated-sources/</output>

<apiPackage>com.example.demo.restclient.api</apiPackage>
<modelPackage>com.example.demo.restclient.model</modelPackage>
<invokerPackage>com.example.demo.restclient</invokerPackage>

<generateApiTests>false</generateApiTests>
<generateModelTests>false</generateModelTests>
<generateApiDocumentation>false</generateApiDocumentation>
<generateModelDocumentation>false</generateModelDocumentation>
<configOptions>
<dateLibrary>java8</dateLibrary>
<sourceFolder>restclient</sourceFolder>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>

The generated HTTP client is based on RestTemplate and will be generated to the folder target/generated-sources/restclient. You may have to configure your IDE to import the generated client in order to use it . (In case of Eclipse, you can configure in Project Properties ➡️ Java Build Path ➡️ Add the folder of the generated rest client)

To start generating the client , just execute the maven command :

mvn clean compile

To use the generated HTTP client :

ApiClient apiClient = new ApiClient();

//Override the default API base path configured in Maven
apiClient.setBasePath("http://api.example.com/api");

EmployeeManagementSystemApi api = new EmployeeManagementSystemApi(apiClient);
api.getEmployeeById(1l);

Note :

  • If you come across javax/xml/bind/annotation/XmlRootElement exception during generation when using java8+ , you may need to refer to this.

JAVA How to do PUT request REST Client

You should use x-www-form-urlencoded because you are not sending any file.

Moreover, you need more work to manually do a form-data request so it's better to change the server so that it accepts x-www-form-urlencoded parameters.

After you have modified the server, add the content type to the request:

connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

and remove this line:

connection.setDoInput(true)

because you use the HttpURLConnection as output.

Note that you can make the PUT request easily with Apache HttpClient.

why are there so many ES java clients?

In short, there have been a few Java clients for historical reasons.

Transport client uses the transport protocol of Elasticsearch, the protocol that nodes use to communicate with each other. There can be compatibility issues if the client is not on the same version as the cluster. The Java client was the only client that used the transport protocol whilst every other client uses the http protocol.

The High Level Rest Client (HLRC) superseded the Transport client and used the http protocol. This was a step in the right direction, however, the client still had dependencies on types from Elasticsearch.

The new Java client supersedes HLRC and is completely decoupled from Elasticsearch. Much of the API surface of the client is generated from an API specification, providing a more maintainable and consistent API surface.

By the way, whilst there have been consistent Nuget packages for the .NET clients (Elasticsearch.Net and NEST) since 1.x, the clients have undergone a fair amount of evolution in this time, with breaking changes between major versions. There's a new .NET for 8.x too (alpha release) :)

Not a REST client interface: interface MyClient. No @Path annotation found on the class or any methods of .... [Quarkus]

So, found the solution.

I added the following build plugins to the module contianing my Client interface


<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<parameters>${maven.compiler.parameters}</parameters>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
</path>
</annotationProcessorPaths>
<!-- the parameters=true option is critical so that RESTEasy works fine -->
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<groupId>org.jboss.jandex</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>1.1.0</version>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

not entirely sure which of those caused the error to get solved really and i wouldn't expect such an error for any of those being missing.



Related Topics



Leave a reply



Submit