Note
|
This repository contains the guide documentation source. To view the guide in published form, view it on the Open Liberty website. |
Learn how to create a REST service with JAX-RS, JSON-B, and Open Liberty.
You will learn how to build and test a simple REST service with JAX-RS and JSON-B, which will expose
the JVM’s system properties. The REST service will respond to GET
requests made to the http://localhost:9080/LibertyProject/System/properties
URL.
The service responds to a GET
request with a JSON representation of the system properties, where
each property is a field in a JSON object like this:
{
"os.name":"Mac",
"java.version": "1.8"
}
When you create a new REST application, the design of the API is important. The JAX-RS APIs could be used to create JSON-RPC, or XML-RPC APIs, but it wouldn’t be a RESTful service. A good RESTful service is designed around the resources that are exposed, and on how to create, read, update, and delete the resources.
The service responds to GET
requests to the /System/properties
path. The GET
request should
return a 200 OK
response that contains all of the JVM’s system properties.
Check out the service at the http://localhost:9080/LibertyProject/System/properties URL.
Navigate to the start
directory to begin.
JAX-RS has two key concepts for creating REST APIs. The most obvious one is the resource itself, which is modelled as a class. The second is a JAX-RS application, which groups all exposed resources under a common path. You can think of the JAX-RS application as a wrapper for all of your resources.
Create theSystemApplication
class.src/main/java/io/openliberty/guides/rest/SystemApplication.java
The SystemApplication
class extends the Application
class, which in turn associates all JAX-RS
resource classes in the WAR file with this JAX-RS application, making them available under the common
path specified in the SystemApplication
class. The @ApplicationPath
annotation has a
value that indicates the path within the WAR that the JAX-RS application accepts requests from.
SystemApplication.java
link:finish/src/main/java/io/openliberty/guides/rest/SystemApplication.java[role=include]
In JAX-RS, a single class should represent a single resource, or a group of resources of the same type. In this application, a resource might be a system property, or a set of system properties. It is easy to have a single class handle multiple different resources, but keeping a clean separation between types of resources helps with maintainability in the long run.
Create thePropertiesResource
class.src/main/java/io/openliberty/guides/rest/PropertiesResource.java
This resource class has quite a bit of code in it, so let’s break it down into manageable chunks.
The @Path
annotation on the class indicates that this resource responds to the properties
path
in the JAX-RS application. The @ApplicationPath
annotation in the SystemApplication
class together with
the @Path
annotation in this class indicates that the resource is available at the System/properties
path.
JAX-RS maps the HTTP methods on the URL to the methods on the class. The method to call is determined
by the annotations specified on the methods. In the application you are building, an HTTP GET
request
to the System/properties
path results in the system properties being returned.
The @GET
annotation on the method indicates that this method is to be called for the HTTP GET
method. The @Produces
annotation indicates the format of the content that will be returned. The
value of the @Produces
annotation will be specified in the HTTP Content-Type
response header.
For this application, a JSON structure is to be returned. The desired Content-Type
for a JSON
response is application/json
with MediaType.APPLICATION_JSON
instead of the String
content type. Using a constant such as MediaType.APPLICATION_JSON
is better because in the event of a spelling error, a compile failure occurs.
JAX-RS supports a number of ways to marshal JSON. The JAX-RS 2.1 specification mandates JSON-Binding (JSON-B) and JAX-B.
The method body returns the result of System.getProperties()
which is of type java.util.Properties
. Since the method
is annotated with @Produces(MediaType.APPLICATION_JSON)
, JAX-RS uses JSON-B to automatically convert the returned object
to JSON data in the HTTP response.
PropertiesResource.java
link:finish/src/main/java/io/openliberty/guides/rest/PropertiesResource.java[role=include]
SystemApplication.java
link:finish/src/main/java/io/openliberty/guides/rest/SystemApplication.java[role=include]
To get the service running, the Liberty server needs to be correctly configured.
Create the server configuration file.
src/main/liberty/config/server.xml
server.xml
link:finish/src/main/liberty/config/server.xml[role=include]
The configuration does the following actions:
-
Configures the server to enable JAX-RS. This is specified in the
featureManager
element. -
Configures the server to resolve the HTTP port numbers from variables, which are then specified in the Maven
pom.xml
file. This is specified in the<httpEndpoint/>
element. Variables use the syntax${variableName}
. -
Configures the server to run the produced Web application on a context root specified in the Maven
pom.xml
file. This is specified in the<webApplication/>
element.
pom.xml
link:finish/pom.xml[role=include]
The variables being used in the server.xml
file are provided by the <bootstrapProperties/>
section
of the Maven pom.xml
.
Check out the service you created at the http://localhost:9080/LibertyProject/System/properties URL.
When you are done checking out the services, stop the Open Liberty server by running the following command:
mvn liberty:stop-server
You could test this service manually by starting a server and pointing a web browser at the http://localhost:9080/LibertyProject/System/properties URL. Automated tests are a much better approach because they will trigger a failure if a change introduces a bug. JUnit and the JAX-RS Client API provide a very simple environment to test the application.
You can write tests for the individual units of code outside of a running application server, or they can be written to call the application server directly. In this example, you will create a test that does the latter.
Create theEndpointTest
class.src/test/java/it/io/openliberty/guides/rest/EndpointTest.java
EndpointTest.java
link:finish/src/test/java/it/io/openliberty/guides/rest/EndpointTest.java[role=include]
This test class has more lines of code than the resource implementation. This situation is common.
The test method is indicated with the @Test
annotation.
pom.xml
link:finish/pom.xml[role=include]
The test code needs to know some information about the application in order to make requests. The server
port and the application context root are key, and are dictated by the server configuration. While this
information can be hardcoded, it is better to specify it in a single place like the Maven pom.xml
file. Refer to the pom.xml
file to see how the application information such as the <app.name/>
, <testServerHttpPort/>
and <testServerHttpsPort/>
elements are provided in the file.
These Maven properties are then passed to the Java test program as the <systemPropertyVariables/>
element in
the pom.xml
file.
Getting the values to create a representation of the URL is simple. The test class uses the getProperty
method
to get the application details.
To call the JAX-RS service using the JAX-RS client, first create a WebTarget
object by calling
the target
method providing the URL. To cause the HTTP request to occur request().get()
is invoked on the WebTarget
. The get
method
call is a synchronous call that blocks until a response is received. This call returns a Response
object, which can be inspected to determine whether the request was successful.
The first thing to check is that a 200
response was received. The JUnit assertEquals
method can
be used for this.
Check the response body to ensure it returned the right information. Since the client and the server
are running on the same machine, it is reasonable to expect that the system properties for the local
and remote JVM would be the same. In this case, an assertion assertEquals
is made that the os.name
system property
for both JVMs is the same. You could write additional assertions to check for more values.
If the server is still running from the previous steps, stop it using the Maven liberty:stop-server
goal from command line in the start directory:
mvn liberty:stop-server
To rebuild, run the tests, and see that the test passes, run the Maven install
command:
mvn install
The Maven build takes a little longer than before the test existed, but expect to see the following information in the output:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.rest.EndpointTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.884 sec - in it.io.openliberty.guides.rest.EndpointTest
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
To see whether the tests detect a failure, add an assertion that you know fails, or change the existing
assertion to a constant value that doesn’t match the os.name
system property.