Consuming a RESTful web service with ReactJS

duration 20 minutes

Prerequisites:

Explore how to access a simple RESTful web service and consume its resources with ReactJS in Open Liberty.

What you’ll learn

You will learn how to access a REST service and deserialize the returned JSON that contains a list of artists and their albums by using an HTTP client with the ReactJS library. You will then present this data by using a ReactJS paginated table component.

ReactJS is a JavaScript library that is used to build user interfaces. Its main purpose is to incorporate a component-based approach to create reusable UI elements. With ReactJS, you can also interface with other libraries and frameworks. Note that the names ReactJS and React are used interchangeably.

The React application in this guide is provided and configured for you in the src/main/frontend directory. The application uses the Create React App prebuilt configuration to set up the modern single-page React application. The create-react-app integrated toolchain is a comfortable environment for learning React and is the best way to start building a new single-page application with React.

artists.json

 1[
 2    {
 3        "id": "1",
 4        "name" : "foo",
 5        "genres": "pop",
 6        "albums" : [
 7            {
 8                "title" : "album_one",
 9                "artist" : "foo",
10                "ntracks" : 12
11            },
12            {
13                "title" : "album_two",
14                "artist" : "foo",
15                "ntracks" : 15
16            }
17        ]
18    },
19    {
20        "id" : "2",
21        "name" : "bar",
22        "genres": "rock",
23        "albums" : [
24            {
25                "title" : "album_rock",
26                "artist" : "bar",
27                "ntracks" : 15
28            }
29        ]
30    },
31    {
32        "id": "3",
33        "name" : "dj",
34        "genres": "hip hop",
35        "albums" : [
36            {
37                "title" : "album_dj",
38                "artist" : "dj",
39                "ntracks" : 7
40            }
41        ]
42    },
43    {
44        "id": "4",
45        "name" : "flow",
46        "genres": "R&B",
47        "albums" : [
48            {
49                "title" : "album_long",
50                "artist" : "flow",
51                "ntracks" : 22
52            }
53        ]
54    },
55    {
56        "id": "5",
57        "name" : "cc",
58        "genres": "country",
59        "albums" : [
60            {
61                "title" : "album_short",
62                "artist" : "cc",
63                "ntracks" : 5
64            }
65        ]
66    },
67    {
68        "id": "6",
69        "name" : "axis",
70        "genres": "classical",
71        "albums" : [
72            {
73                "title" : "album_one",
74                "artist" : "axis",
75                "ntracks" : 9
76            },
77            {
78                "title" : "album_two",
79                "artist" : "axis",
80                "ntracks" : 8
81            },
82            {
83                "title" : "album_three",
84                "artist" : "axis",
85                "ntracks" : 11
86            }
87        ]
88    }
89]

The REST service that provides the resources was written for you in advance in the back end of the application, and it responds with the artists.json in the src/resources directory. You will implement a ReactJS client as the front end of your application, which consumes this JSON file and displays its contents on a single-page webpage.

To learn more about REST services and how you can write them, see the Creating a RESTful web service guide.

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-client-reactjs.git
cd guide-rest-client-reactjs

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. The React front end is already pre-built for you and the static files from the production build can be found in the src/main/webapp/static directory.

To try out the application, navigate 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.

Next, point your browser to the http://localhost:9080 web application root to see the following output:

React Paginated Table

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

Starting the service

Before you begin the implementation, start the provided REST service so that the artist JSON is available to you.

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.

After you start the service, you can find your artist JSON at the http://localhost:9080/artists URL.

All the dependencies for the React front end can be found in src/main/frontend/src/package.json, and they are installed before the front end is built by the frontend-maven-plugin. Additionally, some provided CSS stylesheets files are provided and can be found in the src/main/frontend/src/Styles directory.

Project configuration

The front end of your application uses Node.js to build your React code. The Maven project is configured for you to install Node.js and produce the production files, which are copied to the web content of your application.

Node.js is a server-side JavaScript runtime that is used for developing networking applications. Its convenient package manager, npm, is used to run the React build scripts that are found in the package.json file. To learn more about Node.js, see the official Node.js documentation.

The frontend-maven-plugin is used to install the dependencies that are listed in your package.json file from the npm registry into a folder called node_modules. The node_modules folder can be found in your working directory. Then, the configuration produces the production files to the src/main/frontend/build directory.

The maven-resources-plugin copies the static content from the build directory to the web content of the application.

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
  4    <modelVersion>4.0.0</modelVersion>
  5
  6    <groupId>com.microprofile.demo</groupId>
  7    <artifactId>guide-rest-client-reactjs</artifactId>
  8    <version>1.0-SNAPSHOT</version>
  9    <packaging>war</packaging>
 10
 11    <properties>
 12        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 13        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 14        <maven.compiler.source>1.8</maven.compiler.source>
 15        <maven.compiler.target>1.8</maven.compiler.target>
 16        <!-- Liberty configuration -->
 17        <liberty.var.default.http.port>9080</liberty.var.default.http.port>
 18        <liberty.var.default.https.port>9443</liberty.var.default.https.port>
 19    </properties>
 20
 21    <dependencies>
 22        <!-- Provided dependencies -->
 23        <dependency>
 24            <groupId>jakarta.platform</groupId>
 25            <artifactId>jakarta.jakartaee-api</artifactId>
 26            <version>8.0.0</version>
 27            <scope>provided</scope>
 28        </dependency>
 29        <dependency>
 30            <groupId>org.eclipse.microprofile</groupId>
 31            <artifactId>microprofile</artifactId>
 32            <version>3.3</version>
 33            <type>pom</type>
 34            <scope>provided</scope>
 35        </dependency>
 36
 37        <!-- For tests -->
 38        <dependency>
 39            <groupId>org.junit.jupiter</groupId>
 40            <artifactId>junit-jupiter</artifactId>
 41            <version>5.6.2</version>
 42            <scope>test</scope>
 43        </dependency>
 44    </dependencies>
 45
 46    <build>
 47        <finalName>${project.artifactId}</finalName>
 48        <plugins>
 49            <plugin>
 50                <groupId>org.apache.maven.plugins</groupId>
 51                <artifactId>maven-war-plugin</artifactId>
 52                <version>3.3.1</version>
 53            </plugin>
 54            <!-- Enable liberty-maven plugin -->
 55            <plugin>
 56                <groupId>io.openliberty.tools</groupId>
 57                <artifactId>liberty-maven-plugin</artifactId>
 58                <version>3.2.3</version>
 59            </plugin>
 60            <!-- Frontend resources -->
 61            <!-- tag::frontend-plugin[] -->
 62            <plugin>
 63                <groupId>com.github.eirslett</groupId>
 64                <artifactId>frontend-maven-plugin</artifactId>
 65                <version>1.10.0</version>
 66                <configuration>
 67                    <!-- tag::working-dir[] -->
 68                    <workingDirectory>src/main/frontend</workingDirectory>
 69                    <!-- end::working-dir[] -->
 70                </configuration>
 71                <executions>
 72                    <execution>
 73                        <id>install node and npm</id>
 74                        <goals>
 75                            <goal>install-node-and-npm</goal>
 76                        </goals>
 77                        <configuration>
 78                            <nodeVersion>v12.18.3</nodeVersion>
 79                            <npmVersion>6.14.6</npmVersion>
 80                        </configuration>
 81                    </execution>
 82                    <!-- tag::node-resource-install[] -->
 83                    <execution>
 84                        <id>npm install</id>
 85                        <goals>
 86                            <goal>npm</goal>
 87                        </goals>
 88                        <configuration>
 89                            <arguments>install</arguments>
 90                        </configuration>
 91                    </execution>
 92                    <!-- end::node-resource-install[] -->
 93                    <!-- tag::node-resource-build[] -->
 94                    <execution>
 95                        <id>npm run build</id>
 96                        <goals>
 97                            <goal>npm</goal>
 98                        </goals>
 99                        <configuration>
100                            <arguments>run build</arguments>
101                        </configuration>
102                    </execution>
103                    <!-- end::node-resource-build[] -->
104                    <!-- tag::node-tests[] -->
105                    <execution>
106                        <id>run tests</id>
107                        <goals>
108                            <goal>npm</goal>
109                        </goals>
110                        <configuration>
111                            <arguments>test a</arguments>
112                            <environmentVariables>
113                                <CI>true</CI>
114                            </environmentVariables>
115                        </configuration>
116                    </execution>
117                    <!-- end::node-tests[] -->
118                </executions>
119            </plugin>
120            <!-- end::frontend-plugin[] -->
121            <!-- Copy frontend static files to target directory -->
122            <!-- tag::copy-plugin[] -->
123            <plugin>
124                <groupId>org.apache.maven.plugins</groupId>
125                <artifactId>maven-resources-plugin</artifactId>
126                <version>3.1.0</version>
127                <executions>
128                 <execution>
129                        <id>Copy frontend build to target</id>
130                        <phase>process-resources</phase>
131                        <goals>
132                            <goal>copy-resources</goal>
133                        </goals>
134                        <configuration>
135                            <outputDirectory>
136                                <!-- tag::output-directory[] -->
137                                ${basedir}/src/main/webapp
138                                <!-- end::output-directory[] -->
139                            </outputDirectory>
140                            <resources>
141                                <resource>
142                                    <directory>
143                                        <!-- tag::directory[] -->
144                                        ${basedir}/src/main/frontend/build
145                                        <!-- end::directory[] -->
146                                    </directory>
147                                    <filtering>true</filtering>
148                                </resource>
149                            </resources>
150                        </configuration>
151                    </execution>
152                </executions>
153            </plugin>
154            <!-- end::copy-plugin[] -->
155        </plugins>
156    </build>
157</project>

Creating the default page

You need to create the entry point of your React application. create-react-app uses the index.js file as the main entry point of the application. This JavaScript file corresponds with the index.html file, which is the entry point where your code runs in the browser.

Create the index.js file.
src/main/frontend/src/index.js

index.js

 1// tag::import-react[]
 2import React from 'react';
 3// end::import-react[]
 4// tag::react-dom[]
 5import ReactDOM from 'react-dom';
 6// end::react-dom[]
 7import './Styles/index.css';
 8import App from './Components/App';
 9
10// tag::dom-render[]
11ReactDOM.render(<App />, document.getElementById('root'));
12// end::dom-render[]

index.html

 1<!DOCTYPE html>
 2<html lang="en">
 3  <head>
 4    <title>React App</title>
 5  </head>
 6  <body>
 7    <noscript>You need to enable JavaScript to run this app.</noscript>
 8    <!-- tag::id-root[] -->
 9    <div id="root"></div>
10    <!-- end::id-root[] -->
11  </body>
12</html>

The React library imports the react package. A DOM, or Document Object Model, is a programming interface for HTML and XML documents. React offers a virtual DOM, which is essentially a copy of the browser DOM that resides in memory. The React virtual DOM improves the performance of your web application and plays a crucial role in the rendering process. The react-dom package provides DOM-specific methods that can be used in your application to get outside of the React model, if necessary.

The render method takes an HTML DOM element and tells the ReactDOM to render your React application inside of this DOM element. To learn more about the React virtual DOM, see the ReactDOM documentation.

Creating the React components

A React web application is a collection of components, and each component has a specific function. You will create the components that are used in the application to acquire and display data from the REST API.

App.js

 1import React from 'react';
 2import ArtistTable from './ArtistTable';
 3
 4function App() {
 5  return (
 6    // tag::react-component[]
 7      <ArtistTable/>
 8    // end::react-component[]
 9  );
10}
11
12export default App;

ArtistTable.js

  1// tag::react-library[]
  2import React, { Component } from 'react';
  3// end::react-library[]
  4// tag::axios-library[]
  5import axios from 'axios';
  6// end::axios-library[]
  7// tag::react-table[]
  8import ReactTable from 'react-table-6';
  9import 'react-table-6/react-table.css';
 10// end::react-table[]
 11
 12// tag::class[]
 13class ArtistTable extends Component {
 14// end::class[]
 15  // tag::state-object[]
 16  state = {
 17    posts: [],
 18    isLoading: true,
 19    error: null,
 20  };
 21  // end::state-object[]
 22
 23  // tag::get-posts[]
 24  getArtistsInfo() {
 25    // tag::axios[]
 26    axios('http://localhost:9080/artists')
 27    // end::axios[]
 28      // tag::then-method[]
 29      .then(response => {
 30        // tag::response-data[]
 31        const artists = response.data;
 32        // end::response-data[]
 33        // tag::convert-data[]
 34        const posts = [];
 35        for (const artist of artists) {
 36          // tag::spread-one[]
 37          const { albums, ...rest } = artist;
 38          // end::spread-one[]
 39          for (const album of albums) {
 40            // tag::spread-two[]
 41            posts.push({ ...rest, ...album });
 42            // end::spread-two[]
 43          }
 44        };
 45        // end::convert-data[]
 46        // tag::set-state[]
 47        this.setState({
 48          // tag::data[]
 49          posts,
 50          // end::data[]
 51          isLoading: false
 52        });
 53        // end::set-state[]
 54      // end::then-method[]
 55      })
 56      .catch(error => this.setState({ error, isLoading: false }));
 57  }
 58  // end::get-posts[]
 59
 60  // tag::mount-posts[]
 61  componentDidMount() {
 62    this.getArtistsInfo();
 63  }
 64  // end::mount-posts[]
 65  // tag::render-posts[]
 66  render() {
 67    const { isLoading, posts } = this.state;
 68    // tag::table-info[]
 69    const columns = [{
 70      Header: 'Artist Info',
 71      columns: [
 72        {
 73          Header: 'Artist ID',
 74          accessor: 'id'
 75        },
 76        {
 77          Header: 'Artist Name',
 78          accessor: 'name'
 79        },
 80        {
 81          Header: 'Genres',
 82          accessor: 'genres',
 83        }
 84      ]
 85    },
 86    {
 87      Header: 'Albums',
 88      columns: [
 89        {
 90          Header: 'Title',
 91          accessor: 'title',
 92        },
 93        {
 94          Header: 'Number of Tracks',
 95          accessor: 'ntracks',
 96        }
 97      ]
 98    }
 99  ]
100  // end::table-info[]
101
102  // tag::return-table[]
103  return (
104    <div>
105      <h2>Artist Web Service</h2>
106      {!isLoading ? (
107        // tag::table[]
108        <ReactTable
109          // tag::prop-posts[]
110          data={posts}
111          // end::prop-posts[]
112          // tag::prop-columns[]
113          columns={columns}
114          // end::prop-columns[]
115          defaultPageSize={4}
116          pageSizeOptions={[4, 5, 6]}
117        />) : (
118        // end::table[]
119          <p>Loading .....</p>
120        )}
121    </div>
122    );
123    // end::return-table[]
124  }
125  // end::render-posts[]
126}
127// end::element[]
128
129// tag::export-artisttable[]
130export default ArtistTable;
131// end::export-artisttable[]

The main component in your React application is the App component. You need to create the App.js file to act as a container for all other components.

Create the App.js file.
src/main/frontend/src/Components/App.js

The App.js file returns the ArtistTable component to create a reusable element that encompasses your web application.

Next, create the ArtistTable component that fetches data from your back end and renders it in a table.

Create the ArtistTable.js file.
src/main/frontend/src/Components/ArtistTable.js

The React library imports the react package for you to create the ArtistTable component as inheritance of the React Component and use its values. The state object is initialized to represent the state of the posts that appear on the paginated table. The ArtistTable component also needs to be exported as a reusable UI element that can be used across your application.

To display the returned data, you will use pagination. Pagination is the process of separating content into discrete pages, and it can be used for handling data sets in React. In your application, you’ll render the columns in the paginated table. The columns constant is used to define the table that is present on the webpage.

The return statement returns the paginated table where you defined the properties for the ReactTable. The data property corresponds to the consumed data from the API endpoint and is assigned to the data of the table. The columns property corresponds to the rendered column object and is assigned to the columns of the table.

Importing the HTTP client

Your application needs a way to communicate with and retrieve resources from RESTful web services to output the resources onto the paginated table. The Axios library will provide you with an HTTP client. This client is used to make HTTP requests to external resources. Axios is a promise-based HTTP client that can send asynchronous requests to REST endpoints. To learn more about the Axios library and its HTTP client, see the Axios documentation.

ArtistTable.js

  1// tag::react-library[]
  2import React, { Component } from 'react';
  3// end::react-library[]
  4// tag::axios-library[]
  5import axios from 'axios';
  6// end::axios-library[]
  7// tag::react-table[]
  8import ReactTable from 'react-table-6';
  9import 'react-table-6/react-table.css';
 10// end::react-table[]
 11
 12// tag::class[]
 13class ArtistTable extends Component {
 14// end::class[]
 15  // tag::state-object[]
 16  state = {
 17    posts: [],
 18    isLoading: true,
 19    error: null,
 20  };
 21  // end::state-object[]
 22
 23  // tag::get-posts[]
 24  getArtistsInfo() {
 25    // tag::axios[]
 26    axios('http://localhost:9080/artists')
 27    // end::axios[]
 28      // tag::then-method[]
 29      .then(response => {
 30        // tag::response-data[]
 31        const artists = response.data;
 32        // end::response-data[]
 33        // tag::convert-data[]
 34        const posts = [];
 35        for (const artist of artists) {
 36          // tag::spread-one[]
 37          const { albums, ...rest } = artist;
 38          // end::spread-one[]
 39          for (const album of albums) {
 40            // tag::spread-two[]
 41            posts.push({ ...rest, ...album });
 42            // end::spread-two[]
 43          }
 44        };
 45        // end::convert-data[]
 46        // tag::set-state[]
 47        this.setState({
 48          // tag::data[]
 49          posts,
 50          // end::data[]
 51          isLoading: false
 52        });
 53        // end::set-state[]
 54      // end::then-method[]
 55      })
 56      .catch(error => this.setState({ error, isLoading: false }));
 57  }
 58  // end::get-posts[]
 59
 60  // tag::mount-posts[]
 61  componentDidMount() {
 62    this.getArtistsInfo();
 63  }
 64  // end::mount-posts[]
 65  // tag::render-posts[]
 66  render() {
 67    const { isLoading, posts } = this.state;
 68    // tag::table-info[]
 69    const columns = [{
 70      Header: 'Artist Info',
 71      columns: [
 72        {
 73          Header: 'Artist ID',
 74          accessor: 'id'
 75        },
 76        {
 77          Header: 'Artist Name',
 78          accessor: 'name'
 79        },
 80        {
 81          Header: 'Genres',
 82          accessor: 'genres',
 83        }
 84      ]
 85    },
 86    {
 87      Header: 'Albums',
 88      columns: [
 89        {
 90          Header: 'Title',
 91          accessor: 'title',
 92        },
 93        {
 94          Header: 'Number of Tracks',
 95          accessor: 'ntracks',
 96        }
 97      ]
 98    }
 99  ]
100  // end::table-info[]
101
102  // tag::return-table[]
103  return (
104    <div>
105      <h2>Artist Web Service</h2>
106      {!isLoading ? (
107        // tag::table[]
108        <ReactTable
109          // tag::prop-posts[]
110          data={posts}
111          // end::prop-posts[]
112          // tag::prop-columns[]
113          columns={columns}
114          // end::prop-columns[]
115          defaultPageSize={4}
116          pageSizeOptions={[4, 5, 6]}
117        />) : (
118        // end::table[]
119          <p>Loading .....</p>
120        )}
121    </div>
122    );
123    // end::return-table[]
124  }
125  // end::render-posts[]
126}
127// end::element[]
128
129// tag::export-artisttable[]
130export default ArtistTable;
131// end::export-artisttable[]

The getArtistsInfo() function uses the Axios API to fetch data from your back end. This function is called when the ArtistTable is rendered to the page using the componentDidMount() React lifecycle method.

Update the ArtistTable.js file.
src/main/frontend/src/Components/ArtistTable.js

Add the axios library and the getArtistsInfo() function. Next, add the componentDidMount() method to your component.

The axios HTTP call is used to read the artist JSON that contains the data from the sample JSON file in the resources directory. When a response is successful, the state of the system changes by assigning response.data to posts. The convertData function manipulates the JSON data to allow it to be accessed by the ReactTable. You will notice the object spread syntax that the convertData function uses, which is a relatively new sytnax made for simplicity. To learn more about it, see Spread in object literals.

The this.setState function is used to update the state of your React component with the data that was fetched from the server. This update triggers a rerender of your React component, which updates the table with the artist data. For more information on how state in React works, see the React documentation on state and lifecycle.

Building and packaging the front end

After you successfully build your components, you need to build the front end and package your application. The Maven process-resources goal generates the Node.js resources, creates the front-end production build, and copies and processes the resources into the destination directory.

In a new command-line session, build the front end by running the following command:

mvn process-resources

You can rebuild the front end at any time with the Maven process-resources goal. Any local changes to your JavaScript and HTML are picked up when you build the front end.

Navigate to the http://localhost:9080 web application root to view the front end of your application.

Testing the React client

New projects that are created with create-react-app comes with a test file called App.test.js, which is included in the src/main/frontend/src directory. The App.test.js file is a simple JavaScript file that tests against the App.js component. There are no explicit test cases that are written for this application. The create-react-app configuration uses Jest as its test runner. To learn more about Jest, go to their documentation on Testing React apps.

App.test.js

 1import React from 'react';
 2import { render } from '@testing-library/react';
 3import App from './Components/App';
 4
 5test('renders artist web service title', () => {
 6  const { getByText } = render(<App />);
 7  const titleElement = getByText(/Artist Web Service/i);
 8  expect(titleElement).toBeInTheDocument();
 9});

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
  4    <modelVersion>4.0.0</modelVersion>
  5
  6    <groupId>com.microprofile.demo</groupId>
  7    <artifactId>guide-rest-client-reactjs</artifactId>
  8    <version>1.0-SNAPSHOT</version>
  9    <packaging>war</packaging>
 10
 11    <properties>
 12        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 13        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 14        <maven.compiler.source>1.8</maven.compiler.source>
 15        <maven.compiler.target>1.8</maven.compiler.target>
 16        <!-- Liberty configuration -->
 17        <liberty.var.default.http.port>9080</liberty.var.default.http.port>
 18        <liberty.var.default.https.port>9443</liberty.var.default.https.port>
 19    </properties>
 20
 21    <dependencies>
 22        <!-- Provided dependencies -->
 23        <dependency>
 24            <groupId>jakarta.platform</groupId>
 25            <artifactId>jakarta.jakartaee-api</artifactId>
 26            <version>8.0.0</version>
 27            <scope>provided</scope>
 28        </dependency>
 29        <dependency>
 30            <groupId>org.eclipse.microprofile</groupId>
 31            <artifactId>microprofile</artifactId>
 32            <version>3.3</version>
 33            <type>pom</type>
 34            <scope>provided</scope>
 35        </dependency>
 36
 37        <!-- For tests -->
 38        <dependency>
 39            <groupId>org.junit.jupiter</groupId>
 40            <artifactId>junit-jupiter</artifactId>
 41            <version>5.6.2</version>
 42            <scope>test</scope>
 43        </dependency>
 44    </dependencies>
 45
 46    <build>
 47        <finalName>${project.artifactId}</finalName>
 48        <plugins>
 49            <plugin>
 50                <groupId>org.apache.maven.plugins</groupId>
 51                <artifactId>maven-war-plugin</artifactId>
 52                <version>3.3.1</version>
 53            </plugin>
 54            <!-- Enable liberty-maven plugin -->
 55            <plugin>
 56                <groupId>io.openliberty.tools</groupId>
 57                <artifactId>liberty-maven-plugin</artifactId>
 58                <version>3.2.3</version>
 59            </plugin>
 60            <!-- Frontend resources -->
 61            <!-- tag::frontend-plugin[] -->
 62            <plugin>
 63                <groupId>com.github.eirslett</groupId>
 64                <artifactId>frontend-maven-plugin</artifactId>
 65                <version>1.10.0</version>
 66                <configuration>
 67                    <!-- tag::working-dir[] -->
 68                    <workingDirectory>src/main/frontend</workingDirectory>
 69                    <!-- end::working-dir[] -->
 70                </configuration>
 71                <executions>
 72                    <execution>
 73                        <id>install node and npm</id>
 74                        <goals>
 75                            <goal>install-node-and-npm</goal>
 76                        </goals>
 77                        <configuration>
 78                            <nodeVersion>v12.18.3</nodeVersion>
 79                            <npmVersion>6.14.6</npmVersion>
 80                        </configuration>
 81                    </execution>
 82                    <!-- tag::node-resource-install[] -->
 83                    <execution>
 84                        <id>npm install</id>
 85                        <goals>
 86                            <goal>npm</goal>
 87                        </goals>
 88                        <configuration>
 89                            <arguments>install</arguments>
 90                        </configuration>
 91                    </execution>
 92                    <!-- end::node-resource-install[] -->
 93                    <!-- tag::node-resource-build[] -->
 94                    <execution>
 95                        <id>npm run build</id>
 96                        <goals>
 97                            <goal>npm</goal>
 98                        </goals>
 99                        <configuration>
100                            <arguments>run build</arguments>
101                        </configuration>
102                    </execution>
103                    <!-- end::node-resource-build[] -->
104                    <!-- tag::node-tests[] -->
105                    <execution>
106                        <id>run tests</id>
107                        <goals>
108                            <goal>npm</goal>
109                        </goals>
110                        <configuration>
111                            <arguments>test a</arguments>
112                            <environmentVariables>
113                                <CI>true</CI>
114                            </environmentVariables>
115                        </configuration>
116                    </execution>
117                    <!-- end::node-tests[] -->
118                </executions>
119            </plugin>
120            <!-- end::frontend-plugin[] -->
121            <!-- Copy frontend static files to target directory -->
122            <!-- tag::copy-plugin[] -->
123            <plugin>
124                <groupId>org.apache.maven.plugins</groupId>
125                <artifactId>maven-resources-plugin</artifactId>
126                <version>3.1.0</version>
127                <executions>
128                 <execution>
129                        <id>Copy frontend build to target</id>
130                        <phase>process-resources</phase>
131                        <goals>
132                            <goal>copy-resources</goal>
133                        </goals>
134                        <configuration>
135                            <outputDirectory>
136                                <!-- tag::output-directory[] -->
137                                ${basedir}/src/main/webapp
138                                <!-- end::output-directory[] -->
139                            </outputDirectory>
140                            <resources>
141                                <resource>
142                                    <directory>
143                                        <!-- tag::directory[] -->
144                                        ${basedir}/src/main/frontend/build
145                                        <!-- end::directory[] -->
146                                    </directory>
147                                    <filtering>true</filtering>
148                                </resource>
149                            </resources>
150                        </configuration>
151                    </execution>
152                </executions>
153            </plugin>
154            <!-- end::copy-plugin[] -->
155        </plugins>
156    </build>
157</project>
Update the pom.xml file.
pom.xml

To run the default test, you can add the testing configuration to the frontend-maven-plugin. Rerun the Maven process-resources goal to rebuild the front end and run the tests.

Although the React application in this guide is simple, when you build more complex React applications, testing becomes a crucial part of your development lifecycle. If you need to write application-oriented test cases, follow the official React testing documentation.

When you are done checking the application root, exit dev mode by pressing CTRL+C in the shell session where you ran the server, or by typing q and then pressing the enter/return key.

Great work! You’re done!

Nice work! You just accessed a simple RESTful web service and consumed its resources by using ReactJS in Open Liberty.

Guide Attribution

Consuming a RESTful web service with ReactJS by Open Liberty is licensed under CC BY-ND 4.0

Copied to clipboard
Copy code block
Copy file contents

Prerequisites:

Nice work! Where to next?

What did you think of this guide?

Extreme Dislike Dislike Like Extreme Like

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

Like Open Liberty? Star our repo on GitHub.

Star