{
"os.name":"Mac",
"java.version": "1.8"
}
Creating a RESTful web service
Prerequisites:
Learn how to create a REST service with JAX-RS, JSON-B, and Open Liberty.
What you’ll learn
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:
The design of an HTTP API is essential when creating a web application. The REST API has become the go-to architectural style for building an HTTP API. The JAX-RS API offers functionality for creating, reading, updating, and deleting exposed resources. The JAX-RS API supports the creation of RESTful web services that come with desirable properties, such as performance, scalability, and modifiability.
Getting started
The fastest way to work through this guide is to clone the Git repository and use the projects that are provided inside:
git clone https://github.com/openliberty/guide-rest-intro.git
cd guide-rest-intro
The start
directory contains the starting project that you will build upon.
The finish
directory contains the finished project that you will build.
Try what you’ll build
The finish
directory in the root of this guide contains the finished application. Give it a try before you proceed.
To try out the application, first go to the finish
directory and run the following Maven goal to build the application and deploy it to Open Liberty:
cd finish
mvn liberty:run
After you see the following message, your application server is ready:
The defaultServer server is ready to run a smarter planet.
Check out the service at the http://localhost:9080/LibertyProject/System/properties URL.
After you are finished checking out the application, stop the Open Liberty server by pressing CTRL+C
in the command-line session where you ran the server. Alternatively, you can run the liberty:stop
goal from the finish
directory in another shell session:
mvn liberty:stop
Creating a JAX-RS application
Navigate to the start
directory to begin.
When you run Open Liberty in development mode, known as dev mode, the server listens for file changes and automatically recompiles and deploys your updates whenever you save a new change. Run the following goal to start Open Liberty in dev mode:
mvn liberty:dev
After you see the following message, your application server in dev mode is ready:
Press the Enter key to run tests on demand.
Dev mode holds your command-line session to listen for file changes. Open another command-line session to continue, or open the project in your editor.
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.
Replace theSystemApplication
class.src/main/java/io/openliberty/guides/rest/SystemApplication.java
The SystemApplication
class extends the Application
class, which associates all JAX-RS resource classes in the WAR file with this JAX-RS application. These resources become available under the common path that’s specified with the @ApplicationPath
annotation. The @ApplicationPath
annotation has a value that indicates the path in the WAR file that the JAX-RS application accepts requests from.
SystemApplication.java
Creating the JAX-RS resource
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 of the class by using annotations. Your application uses the GET
annotation to map an HTTP GET
request to the System/properties
path.
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 if there’s 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). 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
SystemApplication.java
Configuring the server
To get the service running, the Liberty server needs to be correctly configured.
Replace the server configuration file.
src/main/liberty/config/server.xml
server.xml
1<server description="Intro REST Guide Liberty server">
2 <!-- tag::featureManager[] -->
3 <featureManager>
4 <feature>jaxrs-2.1</feature>
5 </featureManager>
6 <!-- end::featureManager[] -->
7
8 <!-- tag::httpEndpoint[] -->
9 <httpEndpoint httpPort="${default.http.port}" httpsPort="${default.https.port}"
10 id="defaultHttpEndpoint" host="*" />
11 <!-- end::httpEndpoint[] -->
12
13 <!-- tag::webApplication[] -->
14 <webApplication location="guide-rest-intro.war" contextRoot="${app.context.root}"/>
15 <!-- end::webApplication[] -->
16</server>
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${variableName}
syntax.Configures the server to run the produced web application on a context root specified in the
pom.xml
file. This is specified in the<webApplication/>
element.
pom.xml
1<?xml version='1.0' encoding='utf-8'?>
2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3 <modelVersion>4.0.0</modelVersion>
4
5 <groupId>io.openliberty.guides</groupId>
6 <artifactId>guide-rest-intro</artifactId>
7 <version>1.0-SNAPSHOT</version>
8 <packaging>war</packaging>
9
10 <properties>
11 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
12 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
13 <maven.compiler.source>1.8</maven.compiler.source>
14 <maven.compiler.target>1.8</maven.compiler.target>
15 <!-- Liberty configuration -->
16 <!-- tag::defaultHttpPort[] -->
17 <liberty.var.default.http.port>9080</liberty.var.default.http.port>
18 <!-- end::defaultHttpPort[] -->
19 <!-- tag::defaultHttpsPort[] -->
20 <liberty.var.default.https.port>9443</liberty.var.default.https.port>
21 <!-- end::defaultHttpsPort[] -->
22 <!-- tag::appContextRoot[] -->
23 <liberty.var.app.context.root>LibertyProject</liberty.var.app.context.root>
24 <!-- end::appContextRoot[] -->
25 </properties>
26
27 <dependencies>
28 <!-- Provided dependencies -->
29 <dependency>
30 <groupId>jakarta.platform</groupId>
31 <artifactId>jakarta.jakartaee-api</artifactId>
32 <version>8.0.0</version>
33 <scope>provided</scope>
34 </dependency>
35 <dependency>
36 <groupId>org.eclipse.microprofile</groupId>
37 <artifactId>microprofile</artifactId>
38 <version>3.3</version>
39 <type>pom</type>
40 <scope>provided</scope>
41 </dependency>
42 <!-- For tests -->
43 <dependency>
44 <groupId>org.junit.jupiter</groupId>
45 <artifactId>junit-jupiter</artifactId>
46 <version>5.6.2</version>
47 <scope>test</scope>
48 </dependency>
49 <dependency>
50 <groupId>org.apache.cxf</groupId>
51 <artifactId>cxf-rt-rs-client</artifactId>
52 <version>3.3.6</version>
53 <scope>test</scope>
54 </dependency>
55 <dependency>
56 <groupId>org.apache.cxf</groupId>
57 <artifactId>cxf-rt-rs-extension-providers</artifactId>
58 <version>3.3.6</version>
59 <scope>test</scope>
60 </dependency>
61 <dependency>
62 <groupId>org.eclipse</groupId>
63 <artifactId>yasson</artifactId>
64 <version>1.0.7</version>
65 <scope>test</scope>
66 </dependency>
67 </dependencies>
68
69 <build>
70 <finalName>${project.artifactId}</finalName>
71 <plugins>
72 <!-- Enable liberty-maven plugin -->
73 <plugin>
74 <groupId>io.openliberty.tools</groupId>
75 <artifactId>liberty-maven-plugin</artifactId>
76 <version>3.2.3</version>
77 </plugin>
78 <!-- Plugin to run functional tests -->
79 <plugin>
80 <groupId>org.apache.maven.plugins</groupId>
81 <artifactId>maven-failsafe-plugin</artifactId>
82 <version>2.22.2</version>
83 <configuration>
84 <!-- tag::testsysprops[] -->
85 <systemPropertyVariables>
86 <http.port>${liberty.var.default.http.port}</http.port>
87 <context.root>${liberty.var.app.context.root}</context.root>
88 </systemPropertyVariables>
89 <!-- end::testsysprops[] -->
90 </configuration>
91 </plugin>
92 <plugin>
93 <groupId>org.apache.maven.plugins</groupId>
94 <artifactId>maven-war-plugin</artifactId>
95 <version>3.2.3</version>
96 </plugin>
97 <!-- Plugin to run unit tests -->
98 <plugin>
99 <groupId>org.apache.maven.plugins</groupId>
100 <artifactId>maven-surefire-plugin</artifactId>
101 <version>2.22.2</version>
102 </plugin>
103 </plugins>
104 </build>
105</project>
The variables that are being used in the server.xml
file are provided by the properties set in the Maven pom.xml
file. The properties must be formatted as liberty.var.variableName
.
Running the application
You started the Open Liberty server in dev mode at the beginning of the guide, so all the changes were automatically picked up.
Check out the service that you created at the http://localhost:9080/LibertyProject/System/properties URL.
Testing the service
You can test this service manually by starting a server and pointing a web browser at the http://localhost:9080/LibertyProject/System/properties URL. However, automated tests are a much better approach because they trigger a failure if a change introduces a bug. JUnit and the JAX-RS Client API provide a 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 theEndpointIT
class.src/test/java/it/io/openliberty/guides/rest/EndpointIT.java
EndpointIT.java
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
1<?xml version='1.0' encoding='utf-8'?>
2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3 <modelVersion>4.0.0</modelVersion>
4
5 <groupId>io.openliberty.guides</groupId>
6 <artifactId>guide-rest-intro</artifactId>
7 <version>1.0-SNAPSHOT</version>
8 <packaging>war</packaging>
9
10 <properties>
11 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
12 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
13 <maven.compiler.source>1.8</maven.compiler.source>
14 <maven.compiler.target>1.8</maven.compiler.target>
15 <!-- Liberty configuration -->
16 <!-- tag::defaultHttpPort[] -->
17 <liberty.var.default.http.port>9080</liberty.var.default.http.port>
18 <!-- end::defaultHttpPort[] -->
19 <!-- tag::defaultHttpsPort[] -->
20 <liberty.var.default.https.port>9443</liberty.var.default.https.port>
21 <!-- end::defaultHttpsPort[] -->
22 <!-- tag::appContextRoot[] -->
23 <liberty.var.app.context.root>LibertyProject</liberty.var.app.context.root>
24 <!-- end::appContextRoot[] -->
25 </properties>
26
27 <dependencies>
28 <!-- Provided dependencies -->
29 <dependency>
30 <groupId>jakarta.platform</groupId>
31 <artifactId>jakarta.jakartaee-api</artifactId>
32 <version>8.0.0</version>
33 <scope>provided</scope>
34 </dependency>
35 <dependency>
36 <groupId>org.eclipse.microprofile</groupId>
37 <artifactId>microprofile</artifactId>
38 <version>3.3</version>
39 <type>pom</type>
40 <scope>provided</scope>
41 </dependency>
42 <!-- For tests -->
43 <dependency>
44 <groupId>org.junit.jupiter</groupId>
45 <artifactId>junit-jupiter</artifactId>
46 <version>5.6.2</version>
47 <scope>test</scope>
48 </dependency>
49 <dependency>
50 <groupId>org.apache.cxf</groupId>
51 <artifactId>cxf-rt-rs-client</artifactId>
52 <version>3.3.6</version>
53 <scope>test</scope>
54 </dependency>
55 <dependency>
56 <groupId>org.apache.cxf</groupId>
57 <artifactId>cxf-rt-rs-extension-providers</artifactId>
58 <version>3.3.6</version>
59 <scope>test</scope>
60 </dependency>
61 <dependency>
62 <groupId>org.eclipse</groupId>
63 <artifactId>yasson</artifactId>
64 <version>1.0.7</version>
65 <scope>test</scope>
66 </dependency>
67 </dependencies>
68
69 <build>
70 <finalName>${project.artifactId}</finalName>
71 <plugins>
72 <!-- Enable liberty-maven plugin -->
73 <plugin>
74 <groupId>io.openliberty.tools</groupId>
75 <artifactId>liberty-maven-plugin</artifactId>
76 <version>3.2.3</version>
77 </plugin>
78 <!-- Plugin to run functional tests -->
79 <plugin>
80 <groupId>org.apache.maven.plugins</groupId>
81 <artifactId>maven-failsafe-plugin</artifactId>
82 <version>2.22.2</version>
83 <configuration>
84 <!-- tag::testsysprops[] -->
85 <systemPropertyVariables>
86 <http.port>${liberty.var.default.http.port}</http.port>
87 <context.root>${liberty.var.app.context.root}</context.root>
88 </systemPropertyVariables>
89 <!-- end::testsysprops[] -->
90 </configuration>
91 </plugin>
92 <plugin>
93 <groupId>org.apache.maven.plugins</groupId>
94 <artifactId>maven-war-plugin</artifactId>
95 <version>3.2.3</version>
96 </plugin>
97 <!-- Plugin to run unit tests -->
98 <plugin>
99 <groupId>org.apache.maven.plugins</groupId>
100 <artifactId>maven-surefire-plugin</artifactId>
101 <version>2.22.2</version>
102 </plugin>
103 </plugins>
104 </build>
105</project>
The test code needs to know some information about the application 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 default.http.port
, default.https.port
and app.context.root
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 that provides the URL. To cause the HTTP request to occur, the request().get()
method is called on the WebTarget
object. 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.
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 assertEquals
assertion is made so that the os.name
system property for both JVMs is the same. You can write additional assertions to check for more values.
Running the tests
Because you started Open Liberty in dev mode, press the enter/return
key to run the tests.
You will see the following output:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.rest.EndpointIT
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.884 sec - in it.io.openliberty.guides.rest.EndpointIT
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.
When you are done checking out the service, exit dev mode by pressing CTRL+C
in the command-line session where you ran the server, or by typing q
and then pressing the enter/return
key.
Great work! You’re done!
You just developed a REST service in Open Liberty by using JAX-RS and JSON-B.
Guide Attribution
Creating a RESTful web service by Open Liberty is licensed under CC BY-ND 4.0
Prerequisites:
Nice work! Where to next?
What did you think of this guide?




Thank you for your feedback!
What could make this guide better?
Raise an issue to share feedback
Create a pull request to contribute to this guide
Need help?
Ask a question on Stack Overflow