In this tutorial, we will learn how to create a JAX-RS CRUD example with RESTEasy. The Create, Read, Update, and Delete (CRUD) are the four basic functions of persistent storage.
Before getting started, I would like to give you an overview of JAX-RS Java API.
What is JAX-RS?
JAX-RS (Java API for RESTful Web Services) is a set of Java API that provides support in creating REST APIs. And the framework makes good use of JAX-RS annotations to simplify the development and deployment of these APIs.
JAX-RS 2.0 (JSR-339) and JAX-RS 2.1 (JSR-370), are JCP (Java Community Process) specifications that provide a Java API for RESTful Web Services over the HTTP protocol.
Some of the more well known JAX-RS API implementations are RESTEasy and Jersey.
JAX-RS HTTP annotations
JAX-RS has annotations for responding to HTTP requests.
- @GET - indicates that the annotated method responds to HTTP GET request
- @POST - indicates that the annotated method responds to an HTTP POST request
- @DELETE - indicates that the annotated method responds to an HTTP DELETE request
- @PUT - indicates that the annotated method responds to HTTP PUT request
What is RESTEasy?
RESTEasy is a Java framework for developing RESTful Web Services. It is a fully certified and portable implementation of the JAX-RS 2.0 specification.
RESTEasy provides tighter integration with the JBoss Application Server but we can deploy it on any servlet container like Tomcat, Jetty, etc.
In this tutorial, we use the tomcat server to deploy the RESTEasy web application.
Tools and Technologies used
- JDK 1.8 or later
- Maven 3.5+
- Eclipse IDE
- JAX-RS 2.0 +
- RESTEasy - 3.9.3.Final
- Tomcat 8.5+
Development Steps
- Create a Maven Web project in Eclipse IDE
- Add Maven Dependencies
- Project Structure
- Create a User model class
- Create a UserService class
- Create a UserResource class
- Create an Application Class
- RESTEasy Client for REST API
- Conclusion
1. Create a Maven Web project in Eclipse IDE
Refer below guide to create a web project in eclipse IDE:
https://www.javaguides.net/2018/11/how-to-create-web-project-using-maven-in-eclipse.html
2. Add maven dependencies
Here is the complete Maven pom.xml file. It contains dependencies for RESTEasy, Jackson provider, and RESTEasy client.
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.javaguides</groupId>
<artifactId>resteasy-crud-example-tutorial</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>resteasy-crud-example-tutorial Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<resteasy.version>3.9.3.Final</resteasy.version>
</properties>
<dependencies>
<!-- Set up RESTEasy -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-servlet-initializer</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
<!-- RESTEasy Client Dependency -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>resteasy-crud-example-tutorial</finalName>
</build>
</project>
3. Project Structure
Refer below screenshot for project structure and packaging structure:
4. Create a User model class
This is a User model class. It contains three attributes: id, name, and email.
package net.javaguides.resteasy.model;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class User {
private Long id;
private String name;
private String email;
public User() {
}
public User(Long id, String name, String email) {
super();
this.id = id;
this.name = name;
this.email = email;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", email=" + email + "]";
}
}
5. Create a UserService class
Let's create UserService which provides in-memory storage for user objects. UserService contains CRUD contract methods. We have methods for finding users, saving a user, updating a use, and deleting a user.
package net.javaguides.resteasy.service;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.NotFoundException;
import net.javaguides.resteasy.model.User;
public class UserService {
private List < User > users = new ArrayList < User > ();
public List < User > findAll() {
users.add(new User(100 L, "Ramesh", "ramesh@gmail.com"));
users.add(new User(101 L, "Tny", "tony@gmail.com"));
users.add(new User(102 L, "Tom", "tom@gmail.com"));
return users;
}
public User fetchBy(long id) throws NotFoundException {
for (User user: findAll()) {
if (id == user.getId()) {
return user;
} else {
throw new NotFoundException("Resource not found with Id :: " + id);
}
}
return null;
}
public boolean create(User user) {
return users.add(user);
}
public boolean update(User user) {
for (User updateUser: users) {
if (user.getId().equals(updateUser.getId())) {
users.remove(updateUser);
users.add(user);
return true;
}
}
return false;
}
public boolean delete(Long id) throws NotFoundException {
for (User user: users) {
if (user.getId().equals(id)) {
users.remove(user);
return true;
}
}
return false;
}
}
6. Create UserResource class
Finally, let's see an actual CRUD API definition here:
package net.javaguides.resteasy.resource;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import net.javaguides.resteasy.model.User;
import net.javaguides.resteasy.service.UserService;
/**
* CRUD Rest APIs for User Resource
* @author Ramesh Fadatare
*
*/
@Path("users")
public class UserResource {
private UserService userService = new UserService();
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getUsers() {
List < User > users = userService.findAll();
if (!users.isEmpty()) {
return Response.ok(users).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
@Path("/{id}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getUserById(@PathParam("id") Long id) {
User user = userService.fetchBy(id);
if (user.getId() != null) {
return Response.ok(user).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response createUser(User user) {
boolean result = userService.create(user);
if (result) {
return Response.ok().status(Response.Status.CREATED).build();
} else {
return Response.notModified().build();
}
}
@PUT
@Path("/{id}")
@Consumes(MediaType.APPLICATION_JSON)
public Response updateUser(@PathParam("id") long id, User user) {
boolean result = userService.update(user);
if (result) {
return Response.ok().status(Response.Status.NO_CONTENT).build();
} else {
return Response.notModified().build();
}
}
@Path("/{id}")
@DELETE
@Produces(MediaType.APPLICATION_JSON)
public Response deleteUser(@PathParam("id") Long id) {
boolean result = userService.delete(id);
if (result) {
return Response.ok().status(Response.Status.NO_CONTENT).build();
} else {
return Response.notModified().build();
}
}
}
Let's understand the JAX-RS annotations from the above code:
- The @Path annotation specifies the URL to which the resource responds.
- The @GET annotation indicates that the annotated method responds to HTTP GET requests.
- The @Produces annotation is used to specify the MIME media types of representations a resource can produce and send back to the client.
- When creating a new resource, we use @POST annotation.
- The @Consumes annotation is used to specify which MIME media types of representations a resource can accept, or consume, from the client.
7. Create Application Class
Let's create an application configuration class. The Application defines the components of a JAX-RS application and supplies additional meta-data. The javax.ws.rs.core.Application class is a standard JAX-RS class that you may implement to provide information on your deployment:
package net.javaguides.resteasy.resource;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/restapi")
public class RestEasyServices extends Application {
private Set < Object > singletons = new HashSet < Object > ();
public RestEasyServices() {
singletons.add(new UserResource());
}
@Override
public Set < Object > getSingletons() {
return singletons;
}
}
Notice that with the @ApplicationPath annotation, we set the path to RESTful web services.
8. RESTEasy Client for REST API
Let's create a JUnit test cases to GET, POST, PUT and DELETE Rest web services with RESTEasy:
package net.javaguides.resteasy;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import org.junit.Test;
import net.javaguides.resteasy.model.User;
public class UserResourceTest {
private static final String FULL_PATH = "http://localhost:8080/resteasy-crud-example-tutorial/restapi/users";
@Test
public void testListAllUsers() {
final ResteasyClient client = new ResteasyClientBuilder().build();
final ResteasyWebTarget target = client
.target(FULL_PATH);
String response = target.request().get(String.class);
System.out.println(response);
}
@Test
public void testGetUser() {
final ResteasyClient client = new ResteasyClientBuilder().build();
final ResteasyWebTarget target = client
.target(FULL_PATH + "/100");
Response response = target.request().get();
User user = response.readEntity(User.class);
System.out.println(user.toString());
response.close();
}
@Test
public void testCreateUser() {
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target(FULL_PATH);
Response response = target.request()
.post(Entity.entity(new User(100 L, "Amir", "amir@gmail.com"), "application/json"));
System.out.println(response.getStatus());
response.close();
}
@Test
public void testUpdateUser() {
User user = new User();
user.setName("Ram");
user.setEmail("ram@gmail.com");
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target(FULL_PATH + "/100");
Response response = target.request()
.put(Entity.entity(user, "application/json"));
System.out.println(response.getStatus());
response.close();
}
@Test
public void testDeleteUser() {
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target(FULL_PATH + "/101");
Response response = target.request()
.delete();
System.out.println(response.getStatus());
response.close();
final ResteasyWebTarget target1 = client
.target(FULL_PATH);
String response1 = target1.request().get(String.class);
System.out.println(response1);
}
}
Run above the JUnit test case to test all CRUD REST APIs. Here is the output of JUnit test cases:
Conclusion
In this tutorial, we have created a CRUD RESTFul application with RESTEasy. The application was deployed on Tomcat.
Comments
Post a Comment
Leave Comment