In this tutorial, you will learn developing a RESTful web services API for CRUD operations (Create, Retrieve, Update and Delete), which corresponding to standard HTTP methods POST, GET, PUT and DELETE, using Jersey – an open source REST framework and implementation of JAX-RS (Java API for RESTful Web Services) specification.
To follow this tutorial, suppose that you’re familiar with Java web development using Eclipse IDE, Maven build and Apache Tomcat server. Better if you completed this Hello world RESTful tutorial for beginner.
And make sure that you have the latest versions of Java Development Kit (JDK), Eclipse and Tomcat installed on your computer. In this tutorial, I use JDK 11, Eclipse 2019-09 and Tomcat 9.0. Also you need to have curl program to test the webservices.
org.glassfish.jersey.containers jersey-container-servlet 2.29.1 org.glassfish.jersey.inject jersey-hk2 2.29.1 org.glassfish.jersey.media jersey-media-json-jackson 2.29.1
The first dependency is for Jersey container servlet that processes requests for RESTful webservices. The second one is for an injection library required by Jersey. And the third one is for processing data in JSON format (convert Java objects to JSON and vice-versa). The version 2.29.1 (or newer) works well on JDK 8 or newer (tested with JDK 11).
Then open the web.xml file and insert the following code:
Jersey REST Service org.glassfish.jersey.servlet.ServletContainer jersey.config.server.provider.packages net.codejava.ws 1 Jersey REST Service /rest/*
This is to specify Jersey Container servlet is responsible to handle all requests coming to the web application with URL starts with /rest/ (after the webapp’s context path). We also specify the package net.codejava.ws contains RESTful webservices classes to be exposed to the clients.
We will develop RESTful webservices API that allow clients to do CRUD operations on products, so create a domain model class as simple as follows:
package net.codejava.ws; public class Product < private int id; private String name; private float price; public Product(int id) < this.id = id; >public Product() < >public Product(int id, String name, float price) < this.id = id; this.name = name; this.price = price; >// getters and setters are not shown for brevity @Override public int hashCode() < final int prime = 31; int result = 1; result = prime * result + id; return result; >@Override public boolean equals(Object obj) < if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Product other = (Product) obj; if (id != other.id) return false; return true; >>
As you can see, in this model class we implement equals() and hashCode() based on product ID so a Product object can be found in an ArrayList as shown below in the DAO class.
For the shake of simplicity, I don’t use a real database. Instead, I code a DAO class with some mock data so we can focus on the RESTful webservices methods for CRUD operations. Create the ProductDAO class with the following code:
package net.codejava.ws; import java.util.ArrayList; import java.util.List; public class ProductDAO < private static ProductDAO instance; private static Listdata = new ArrayList<>(); static < data.add(new Product(1, "iPhone X", 999.99f)); data.add(new Product(2, "XBOX 360", 329.50f)); >private ProductDAO() < >public static ProductDAO getInstance() < if (instance == null) < instance = new ProductDAO(); >return instance; > public List listAll() < return new ArrayList(data); > public int add(Product product) < int newId = data.size() + 1; product.setId(newId); data.add(product); return newId; >public Product get(int id) < Product productToFind = new Product(id); int index = data.indexOf(productToFind); if (index >= 0) < return data.get(index); >return null; > public boolean delete(int id) < Product productToFind = new Product(id); int index = data.indexOf(productToFind); if (index >= 0) < data.remove(index); return true; >return false; > public boolean update(Product product) < int index = data.indexOf(product); if (index >= 0) < data.set(index, product); return true; >return false; > >
As you can see, this DAO class implements CRUD operations to manage products. It will be used by RESTful web services class in the next section below.
Hands-on REST API Development with Spring Boot: Design, Implement, Document, Secure, Test, Consume RESTful APIs
Now, let’s code a RESTful webservices class that provides REST API for the clients. Write the initial code as below:
package net.codejava.ws; import java.net.*; import java.util.*; import javax.ws.rs.*; import javax.ws.rs.core.*; @Path("/products") public class ProductResource < private ProductDAO dao = ProductDAO.getInstance(); // RESTful API methods go here. >Then write code to implement API method for each operation in the CRUD.\
This method serves HTTP GET request and returns a list of products in JSON format. Type the following command to test with curl:
curl http://localhost:8080/MyWebsite/rest/productsResponse from the server:
NOTE: The best practice for this retrieval operation is returning HTTP status code 204 No Content if no data in the response. Hence update the code as below:
@GET @Produces(MediaType.APPLICATION_JSON) public Response list() < ListlistProducts = dao.listAll(); if (listProducts.isEmpty()) < return Response.noContent().build(); >return Response.ok(listProducts).build(); >
@GET @Path("") @Produces(MediaType.APPLICATION_JSON) public Response get(@PathParam("id") int id) < Product product = dao.get(id); if (product != null) < return Response.ok(product, MediaType.APPLICATION_JSON).build(); >else < return Response.status(Response.Status.NOT_FOUND).build(); >>
This method returns information of a particular product based on a given product ID. If a product is found, it returns the response with HTTP 200 status and includes JSON data of the product. Command to test:
curl http://localhost:8080/MyWebsite/rest/products/2Response from the server:
@POST @Consumes(MediaType.APPLICATION_JSON) public Response add(Product product) throws URISyntaxException < int newProductId = dao.add(product); URI uri = new URI("/products/" + newProductId); return Response.created(uri).build(); >
As you can see, this method serves HTTP POST request and requires content type of JSON posted from the client. It returns a Response object with HTTP 201 (Created) status and the URI of the newly added item. Run the following command to test (type all in one line):
curl -v -X POST -H "Content-Type: application/json" -d "" http://localhost:8080/MyWebsite/rest/products/The server’s response includes something like this:
HTTP/1.1 201 Location: http://localhost:8080/products/3 Content-Length: 0
The following method exposes a RESTful API that allows the client to update a product with a given ID:
@PUT @Consumes(MediaType.APPLICATION_JSON) @Path("") public Response update(@PathParam("id") int id, Product product) < product.setId(id); if (dao.update(product)) < return Response.ok().build(); >else < return Response.notModified().build(); >>
As you can see, this method requires HTTP PUT method and application/json content type. ID of the product is passed as a path parameter in the request URI. If the product is update successfully, return HTTP 200 (OK) status. Else if the product is not found, return HTTP 304 (Not Modified) status.
Run this command to update the product with ID 1:
curl -v -X PUT -H "Content-Type: application/json" -d "" http://localhost:8080/MyWebsite/rest/products/1You can see the following information in the server’s response:
HTTP/1.1 200 Content-Length: 0If you try to update a product with non-exist ID, the server will return this response:
HTTP/1.1 304
@DELETE @Path("") public Response delete(@PathParam("id") int id) < if (dao.delete(id)) < return Response.ok().build(); >else < return Response.notModified().build(); >>
You see, this method requires HTTP DELETE method with ID of the product as a path parameter in the request URI. If the product is removed successfully, the server returns HTTP 200 (OK) status; else returns HTTP 304 (Not Modified) status.
Type the following command to test:
curl -v -X DELETE http://localhost:8080/MyWebsite/rest/products/2This will remove the product with ID 2.
NOTE: the best practice for delete operation if successful is returning HTTP status code 204 No Content. So update the code as below:
if (dao.delete(id))In this section, I will guide you how to code a client program to consume RESTful web services using Jersey Client API. Create a new client project and add the following dependencies to the pom.xml file:
Write initial code for the client program as follows:org.glassfish.jersey.core jersey-client 2.29.1 org.glassfish.jersey.inject jersey-hk2 2.29.1 org.glassfish.jersey.media jersey-media-json-jackson 2.29.1 org.glassfish.jaxb jaxb-runtime 2.3.2
package net.codejava.ws; import javax.ws.rs.client.*; import javax.ws.rs.core.*; import org.glassfish.jersey.client.ClientConfig; public class ProductClientTest < private static String baseURI = "http://localhost:8080/MyWebsite/rest/products"; static WebTarget getWebTarget() < ClientConfig config = new ClientConfig(); Client client = ClientBuilder.newClient(config); return client.target(baseURI); >public static void main(String[] args) < // call a test method: testList(), testAdd(), testGet(). >>To test listing all items, code the following method: static void testList()
Test to get a specific item by ID:
static void testGet()Test to add a new item:
static void testAdd()The following method tests updating an item:
private static void testUpdate()And code the method that tests deleting an item as follows:
private static void testDelete() That’s how to code a RESTful webservices client program to test CRUD operations.So far you have learned how to code a RESTful webservices application with CRUD (Create, Retrieve, Update and Delete) operations. I hope you found this tutorial helpful. And for your reference, you can download the sample project in the attachments section below. You can also get code from GitHub here.
You can also watch the video version below:
What's Next? I recommend you follow this one: Spring Boot Hello World RESTful Web Services Tutorial
Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.
JavaCrudRestfulWS.zip | [Java CRUD RESTful Web Services Sample Projects] | 30 kB |