Rendering RESTful service with React

Looking at the popularity of React, I thought of learning it and creating a simple UI which will render data from RESTful service.

With this post, I will try to replicate the steps I followed while writing it along with references. Before starting, let me give you a brief introduction about React.

What is React?

React is a declarative, efficient, and flexible JavaScript library for building user interfaces. It uses virtual DOM which improve apps performance since JavaScript virtual DOM is faster than the regular DOM with a limitation that it only covers view layer of the app so you still need to choose other technologies to get a complete tooling set for development.

Now, lets’ start with creating react-app running on port 8080, following below steps:

Step 1: Go to start.spring.io and create a new project react-app adding the Thymeleaf starters, based on the following image:

Screen Shot 2017-05-06 at 2.53.30 pm.png
Step 2: Edit ReactAppApplication.java to add a method which returns a list of employee, as follows:

package com.arpit.react.app;

import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class ReactAppApplication {

	public static void main(String[] args) {
		SpringApplication.run(ReactAppApplication.class, args);
	}

	@GetMapping("/employee/get")
	public List<Employee> get() {
		List<Employee> employeeList = new ArrayList<>();
		employeeList.add(new Employee(1, "Arpit", "IT"));
		employeeList.add(new Employee(2, "Sanjeev", "IT"));
		return employeeList;
	}
}

@Controller
class IndexPageController {

	@GetMapping(value = "/")
	public String index() {
		return "index";
	}
}

final class Employee {

	private int id;
	private String name;
	private String department;

	public Employee() {

	}

	public Employee(final int id, final String name, final String department) {
		this.id = id;
		this.name = name;
		this.department = department;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDepartment() {
		return department;
	}

	public void setDepartment(String department) {
		this.department = department;
	}
}

IndexPageController define index() method flagged by @GetMapping(value = “/”) to support the / route. It returns index as the name of the template, which Spring Boot’s autoconfigured view resolver will map to src/main/resources/templates/index.html.

Step 3: Define an HTML template src/main/resources/templates/index.html with the following content:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8" />
<title>React with Spring REST</title>
</head>
<body>
	<div id="react"></div>
	<script src="package/script.js"></script>
</body>
</html>

Step 4: Move to react-app directory and run command: mvn spring-boot:run. Once running open http://localhost:8080/employee/get which will give you the list of employees we are going to render on UI built with React.

Step 5: Next we will add frontend-maven-plugin in pom.xml  to install Node and NPM locally for the react-app followed by running Webpack  build, as follows:

<plugin>
				<groupId>com.github.eirslett</groupId>
				<artifactId>frontend-maven-plugin</artifactId>
				<version>1.2</version>
				<configuration>
					<installDirectory>target</installDirectory>
				</configuration>
				<executions>
					<execution>
						<id>install node and npm</id>
						<goals>
							<goal>install-node-and-npm</goal>
						</goals>
						<configuration>
							<nodeVersion>v4.4.5</nodeVersion>
							<npmVersion>3.9.2</npmVersion>
						</configuration>
					</execution>
					<execution>
						<id>npm install</id>
						<goals>
							<goal>npm</goal>
						</goals>
						<configuration>
							<arguments>install</arguments>
						</configuration>
					</execution>
					<execution>
						<id>webpack build</id>
						<goals>
							<goal>webpack</goal>
						</goals>
					</execution>
				</executions>
</plugin>

Step 6: Execute npm init in the root directory to create package.json in which we specify all the dependencies required to build our react-app like React, React DOM, Webpack, Babel Loader, Babel Core, Babel Preset: ES2015, Babel Preset: React, as follows:

$ cd react-app
$ touch npm init

Copy the following content:

{
  "name": "react-app",
  "version": "1.0.0",
  "description": "Rendering RESTful service with React",
  "repository": {
    "type": "git",
    "url": "git@github.com:arpitaggarwal/react-app.git"
  },
  "keywords": [
    "rest",
    "spring",
    "react"
  ],
  "author": "Arpit Aggarwal",
  "dependencies": {
    "axios": "^0.16.1",
    "react": "^15.3.2",
    "react-dom": "^15.3.2",
    "webpack": "^1.12.2"
  },
  "scripts": {
    "watch": "webpack --watch -d"
  },
  "devDependencies": {
    "babel-core": "^6.18.2",
    "babel-loader": "^6.2.7",
    "babel-polyfill": "^6.16.0",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-react": "^6.16.0"
  }
}

Step 7: Next we will create webpack.config.js to configure webpack, as follows:

$ cd react-app
$ touch webpack.config.js

Copy the following content:

var path = require('path');

module.exports = {
    entry: './app/main.js',
    cache: true,
    debug: true,
    output: {
        path: __dirname,
        filename: './src/main/resources/static/package/script.js'
    },
    module: {
        loaders: [
            {
                test: path.join(__dirname, '.'),
                exclude: /(node_modules)/,
                loader: 'babel',
                query: {
                    cacheDirectory: true,
                    presets: ['es2015', 'react']
                }
            }
        ]
    }
};

entry option specified above is the entry point for the bundle.
cache option specified above Cache generated modules and chunks to improve performance for multiple incremental builds.
output option specified above tell Webpack how to write the compiled files to disk.

For more configuration options you can explore here.

Step 8: Next we will create entry point for the webpack which is react-app/app/main.js, as:

$ cd react-app
$ mkdir app
$ cd app
$ touch main.js

Copy the following content:

'use strict';
const React = require('react');
const ReactDOM = require('react-dom')

import ReactApp from './components/react-app.jsx'

ReactDOM.render(
		<ReactApp />,
	document.getElementById('react')
)

React is the main library from Facebook for building the app.
ReactDOM provides DOM-specific methods that can be used at the top level.
ReactApp is the top level container for all React components.

Let’s define ReactApp along with it’s child components, as:

$ cd react-app/app/
$ mkdir components
$ cd components
$ touch react-app.jsx employee-list.jsx employee.jsx 

react-spring/app/components/react-app.jsx

'use strict';
const React = require('react');
var axios = require('axios');

import EmployeeList from './employee-list.jsx'

export default class ReactApp extends React.Component {

	constructor(props) {
		super(props);
		this.state = {employees: []};
		this.Axios = axios.create({
		    baseURL: "/employee",
		    headers: {'content-type': 'application/json', 'creds':'user'}
		});
	}

	componentDidMount() {
		let _this = this;
		this.Axios.get('/get')
		  .then(function (response) {
		     console.log(response);
		    _this.setState({employees: response.data});
		  })
		  .catch(function (error) {
		    console.log(error);
		  });
	}

	render() {
		return (
				<div>
				  <EmployeeList employees={this.state.employees}/>
		        </div>
			)
	}
}

react-spring/app/components/employee-list.jsx

const React = require('react');
import Employee from './employee.jsx'

export default class EmployeeList extends React.Component{
    
    render() {
		var employees = this.props.employees.map((employee, i) =>
			<Employee key={i} employee={employee}/>
		);
		
		return (
			<table>
				<tbody>
					<tr>
						<th>ID</th>
						<th>Name</th>
						<th>Department</th>
					</tr>
					{employees}
				</tbody>
			</table>
		)
	}
}

react-spring/app/components/employee.jsx

const React = require('react');

export default class Employee extends React.Component{
	render() {
		return (
			<tr>
				<td>{this.props.employee.id}</td>
				<td>{this.props.employee.name}</td>
				<td>{this.props.employee.department}</td>
			</tr>
		)
	}
}

With all this in place, your directory structure should look like:

Screen Shot 2017-05-06 at 4.49.26 pm

Now re-run the application and visit http://localhost:8080.

Complete source code is hosted on github.

Fixing com.couchbase.client.java.error.TranscodingException: Could not encode document with ID cache:EMPLOYEE_:1 – Couchbase

If you are using couchbase spring cache then you might get following exception:


Error occured: Details com.couchbase.client.java.error.TranscodingException: Could not encode document with ID cache:EMPLOYEE_:1

This exception is raised by couchbase client when document is not able to serialized, possible use case is when you are caching the resource which contain nested objects and does not implement Serializable, for example:

Employee.java


public class Employee {

   private int id;
   private String name;
   private Address address;
}

Address.java


 public class Address {
   private String city;
   private String country;
}

If you are facing the same problem as me then you can fix it implementing Serializable in all the classes, as follows:

Employee.java

import java.io.Serializable;

public class Employee implements Serializable {

  private static final long serialVersionUID = 1L;
  private int id;
  private String name;
  private Address address;
}

Address.java

import java.io.Serializable;

public class Address implements Serializable {

  private static final long serialVersionUID = 1L;
  private String city;
  private String country;

}

Fixing com.couchbase.client.java.error.DocumentDoesNotExistException – Couchbase

If you are using couchbase spring cache then you might get following exception:


12:16:58,338 ERROR [com.arpit.common.util.Resource] (http-/127.0.0.1:8080-6) Error occured: Details com.couchbase.client.java.error.DocumentDoesNotExistException

This exception is raised by couchbase client when document does not exist in cache and a replace operation is used, possible use case is when you are caching the resource which return null (which was happening for me), for example:

@Override
@Cacheable(value = "EMPLOYEE_", key = "#id")
public Employee getEmployee(int id) {
	return null;
}

If you are facing the same problem as me then you can fix it using the unless attribute of @Cacheable which is available as of Spring 3.2, as follows:

@Override
@Cacheable(value = "EMPLOYEE_", key = "#id", unless = "#result == null")
public Employee getEmployee(int id) {
	return null;
}

Setting TTL for @Cacheable – Spring

Today I was asked to set the expiry time of cache for some of the keys our application is using, so I quickly started looking for all of the options provided by Spring @Cacheable notation to set up the expiry time or time to live. Since Spring does not provide any configurable option to achieve it, I build one implementation leveraging @Scheduled annotation with a fixed delay, as follows:


@CacheEvict(allEntries = true, cacheNames = { "EMPLOYEE_", "MANAGER_" })
@Scheduled(fixedDelay = 30000)
public void cacheEvict() {
}

Now the problem is I want cache names as well as the fixed delay time period should be populated from environmental values instead of hard coded values. To achieve the same I declared variables(populated from properties file) at class level and populated the values of the key in the annotation which made IDE to complain that values must be constant, as follows:

“The value for annotation attribute CacheEvict.cacheNames must be a constant expression”

Then I started looking for other options to get the values for the keys from environment and came across fixedDelayString element of @Scheduled notation which helped me to achieve my goal, as follows:


@Scheduled(fixedDelayString = "${couchbase.cache.flush.fixed.delay}")
public void cacheEvict() {
}

Looking for the similar element for @CacheEvict annotation as well, which is unfortunately not available given me a hint after reading the the comment on a bug SPR-10778 which says:

“The cache abstraction supports the CacheResolver abstraction now and it can be specified globally, per class and/or on a specific operation. The CacheResolver give you the ability to compute the caches to use in code so you have all the flexibility that you want.”

As bug says to make use of CacheResolver to dynamically populate the cache names, I used AbstractCacheResolver implementation of it to get the names of cache from environment, as follows:


@Value("#{'${couchbase.cache.flush}'}")
private String couchbaseCacheFlush;

@Bean(name = "customCacheResolver")
	public CacheResolver cacheResolver() {
		CacheResolver cacheResolver = new AbstractCacheResolver(cacheManager()) {
			@Override
			protected Collection<String> getCacheNames(
					CacheOperationInvocationContext<?> context) {
				return Arrays.asList(couchbaseCacheFlush.split(","));
			}
		};
		return cacheResolver;
	}

Modifying the cacheEvict() to use custom cache resolver instead of cache names completed my task for the day, as follows:


@CacheEvict(allEntries = true, cacheResolver = "customCacheResolver")
@Scheduled(fixedDelayString = "${couchbase.cache.flush.fixed.delay}")
public void cacheEvict() {
}

Complete source is available on github.

Permission denied executing shell script on remote host using ssh – Jenkins

Today I was setting up a Jenkins pipeline for one of my project and noticed deploy job fails every time it try to execute the script on a remote Linux machine stating the reason – “Build step ‘Execute shell script on remote host using ssh’ marked build as failure”, as follows:

executing script:

./stage-deployment/scripts/stage-node_deploy.sh
bash: line 1: ./stage-deployment/scripts/stage-node_deploy.sh: Permission denied
[SSH] exit-status: 126
Build step 'Execute shell script on remote host using ssh' marked build as failure

If you are facing the same problem as me then you can fix it after changing the permissions of a directory containing executable, as:

chmod --recursive a+rwx /stage-deployment/scripts/

Expected Exception Rule and Mocking Static Methods – JUnit

Today I was asked to consume a RESTful service so I started implementing it following Robert Cecil Martin’s rules for TDD and came across a new way (atleast for me) of testing the expected exception along with the error message so thought of sharing the way I implemented it as part of this post.

To start with let’s write a @Test and specify rule that our code will throw a specific exception for our example it’s EmployeeServiceException which we will verify it using ExpectedException which will provide us more precise information about the exception expected to be thrown with the ability to verify error message, as follows:


@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassWithStaticMethod.class)
public class EmployeeServiceImplTest {

	@InjectMocks
	private EmployeeServiceImpl employeeServiceImpl;

	@Rule
	public ExpectedException expectedException = ExpectedException.none();

	@Before
	public void setupMock() {
		MockitoAnnotations.initMocks(this);
	}

	@Test
	public void addEmployeeForNull() throws EmployeeServiceException {
		expectedException.expect(EmployeeServiceException.class);
		expectedException.expectMessage("Invalid Request");
		employeeServiceImpl.addEmployee(null);
	}

}

Now we will create an implementing class for our @Test which will throw EmployeeServiceException whenever the request is null, for me it’s EmployeeServiceImpl as follows:

EmployeeServiceImpl.java


public class EmployeeServiceImpl implements IEmployeeService {

	@Override
	public String addEmployee(final Request request)
			throws EmployeeServiceException {
		if (request == null) {
			throw new EmployeeServiceException("Invalid Request");
		}
		return null;
	}
}

Next we will write a @Test where we will mock static method which accepts input parameters with return type using PowerMockito.mockStatic(), verify it using PowerMockito.verifyStatic() and finally do an Assert to record test pass or failure status, as follows:


@Test
	public void addEmployee() throws EmployeeServiceException {
		PowerMockito.mockStatic(ClassWithStaticMethod.class);
		PowerMockito.when(ClassWithStaticMethod.getDetails(anyString()))
				.thenAnswer(new Answer<String>() {
					@Override
					public String answer(InvocationOnMock invocation)
							throws Throwable {
						Object[] args = invocation.getArguments();
						return (String) args[0];
					}
				});
		final String response = employeeServiceImpl.addEmployee(new Request(
				"Arpit"));
		PowerMockito.verifyStatic();
		assertThat(response, is("Arpit"));
	}

Now we will provide the implementation for our @Test inside EmployeeServiceImpl itself. To do that, lets modify the EmployeeServiceImpl to have static method call as part of else statement of addEmployee, as follows:


public class EmployeeServiceImpl implements IEmployeeService {

	@Override
	public String addEmployee(final Request request)
			throws EmployeeServiceException {
		if (request == null) {
			throw new EmployeeServiceException("Invalid Request");
		} else {
			return ClassWithStaticMethod.getDetails(request.getName());
		}
	}
}

Where getDetails is a static method inside ClassWithStaticMethod:


public class ClassWithStaticMethod {

	public static String getDetails(String name) {
		return name;
	}
}


 
Complete source code is hosted on github.

Sending E-mails with Node.JS

In post Writing Restful Service Using Node, Express and Mongodb we created a rest api which creates, delete and get employees from database, this time we will send e-mail over Gmail SMTP server using Nodemailer, as follows:

Create a directory and execute npm init, as follows:

$ cd /Users/ArpitAggarwal/
$ mkdir node-js-send-mail
$ cd /node-js-send-mail
$ npm init

Next, install Nodemailer as a dependency and create server.js which is the default entry point for Node.js to send email:

$ cd /Users/ArpitAggarwal/node-js-send-mail
$ npm install --save nodemailer
$ touch server.js

Copy below content in server.js:


var nodemailer = require('nodemailer');

var smtpConfig = {
    host: 'smtp.gmail.com',
    port: 465,
    secure: true, // use SSL
    auth: {
        user: 'aggarwalarpit.89',
        pass: 'XXXXXX'
    }
};

var transporter = nodemailer.createTransport(smtpConfig);

// setup e-mail data with unicode symbols
var mailOptions = {
    from: '"Arpit Aggarwal 👥" <aggarwalarpit.89@gmail.com>', // sender address
    to: 'aggarwalarpit.89@gmail.com, aggarwalarpit.89@gmail.com', // list of receivers
    subject: 'Hello from Nodemailer ✔', // Subject line
    text: 'Hello Node', // plaintext body
    html: '<b>✌</b>' // html body
};

transporter.sendMail(mailOptions, function(error, info){
    if(error){
        return console.log(error);
    }
    console.log('Message sent: ' + info.response);
});

Next, move to directory /Users/ArpitAggarwal/node-js-send-mail start the app following below command:

$ cd /Users/ArpitAggarwal/node-js-send-mail
$ node server.js

Reference: https://github.com/nodemailer/nodemailer