reset service test

RESTFul webservices with Jersey And Spring

JAX-RS and Jersey

JAX-RS, is the “Java™ API for RESTful Web Services (JAX-RS)”. Documented in JSR 311 & JSR 339 it specifies a bunch of interfaces and annotations that can be used to define RESTful Webservices in java.

Jersey is a reference implementation of JAX-RS Spec. In addition to implementing the JSR 331 and 339, JAX-RS provides its own extensions to the JAX-RS API. Although Jersey is a good starting point, any other JAX-RS implementation can be used in its place as well.

Also JAX-RS webservices can be created standalone, i.e., without Spring. However, using Spring along with Jersey makes it easier to build and scale the webservices due to the ability to use DI, Data access and data representation (e.g., JSON/XML Marshalling), Security, Enterprise Integration and other powerful features of Spring.

Create a new Jersey Webservice with Spring

In this article we will be creating RESTFul webservices with Jersey & Spring. We will be using the Spring Tool Suite (STS) for this purpose and in the screenshots. However we can also use maven on the command-line and eclipse and achieve the same results. In this example we will create a web-service that will provide a REST API to manage a collection of films. The client can retrieve the list of films in the collection along with their year of release and other details. add films to it, modify individual films’ attributes as well as delete films from it.

To get started, download STS from its download page. Choose the appropriate platform and architecture and download. Extract and launch the executable named “STS” to start Spring Tools Suite.

Before you continue following the steps outline below make sure you have an active internet connection. This is because STS/Maven download the project dependencies automatically from the internet as needed.

Use File -> New Spring Starter Project to create a new Spring starter project.

spring tools suite new project
spring tools suite new project

In the dialog that opens up enter the artifact ID, group ID and package name as desired and leave the rest to the defaults as shown in the screenshot.

spring tools suite new maven project
spring tools suite new maven project

Click Next and in the “New Spring Starter Dependencies” screen select Jersey (within Web).

spring starter project dependencies
spring starter project dependencies

Click Finish for STS to create the project. Wait for the background process to finish downloading and setting up the project. (Progress Tab shows the status)

The STS creates the project directory structure and downloads all the dependencies. As we can see it is a typical maven project structure with all the java source files located in src/main/java, the unit tests and automated tests in src/test/java and a pom.xml in the project root directory.

The project has a parent tag pointing to the latest stable release of spring. It has the spring-boot-starter-jersey dependency to ensure Jersey and its dependencies are pulled in. Finally the spring-boot-maven-plugin adds the maven build capabilities to the project. A quick look at the project properties under dependencies confirms we have the necessary dependencies added.

All the classes we will create for the rest of the article will be in src/main/java within the com.javagists.jerseyfilms package.

Anatomy of a JAX-RS Webservice

Generally a JAX-RS webservice has 1 or more Root resource classes, a JerseyConfiguration class, an (optional) ExceptionMapper class and the Spring boot Application class in addition to domain classes which implement the business logic (model, persistence, etc.,.).

The Root Resource Class(es)

As we saw earlier, providing a REST API is essentially about making resources accessible via well-defined URI (endpoints) and implementing the Uniform interface on these. In JAX-RS, this is accomplished by creating a Root resource class which is a Java Class that uses JAX-RS annotations like @Path to implement a corresponding Web Resource. They are essentially POJOs that have a class-level annotation or a method level annotation. We will be shortly looking at these annotations and what they mean.

First let’s create a FilmController class that will be our Root Resource Class. We’ll create a new package called controller and create FilmController inside this package. The source code for FilmController.java is given below.

The class has a @Path annotation which indicates the base-path of the web resource. In this case the web resource implemented by FilmController class will be accessible at http://localhost:8080/films. The films() method has a @GET tag, meaning whenever a GET request is received at this end-point this method will be invoked. Finally it has an @Produces tag which indicates the type of response produced, in this case, “application/json”.

Notice how the method returns has a return type of Collection — the conversion into JSON is handled automatically by the platform (more specifically, by the Jackson library that was included as a dependency when we created the Spring Starter app with Jersey).

Next is the add method. The @POST tag indicates this is the handler for POST requests, the @Consumes tag indicates the type of input data. The @Path tag has "/{id}" which is to indicate that the path to this resource is obtained by adding an id suffix to the base-path of the class – for example, http://localhost:8080/films/2. The value of this suffix is set to the id parameter of the function by decorating it with @PathParam{"id"}. The method returns a success response code of 201, which is the standard code for successful resource creation, along with a link to the newly created resource. In real-life scenario this method will check for id collision or other errors and handle or report error – we skip that for sake of simplicity now. Further down in the article we will look at how we can handle errors.

Helper Classes

The JerseyConfiguration class registers the Root resource classes. This is an implementation detail of Jersey. Below is the source code for this file. It just registers the one Root Resource class that we have created.

The JerseyFilmsApplication has the @SpringBootApplication decorator – it bootstraps and starts our Spring Boot App. This is generated by STS and can be used to configure application level properties such as the base-path for the application.

Domain classes

The FilmController class we created above depends on the FilmService and Film Classes. We create the service and model packages to house these classes.

The Film Class is our data model and encapsulates the information about a Film.

Genre is an enum defined in Genre.java

The FilmService class maintains the collection of films.

In our example, we initialise the collection to an empty list. However in a real-life scenario we could connect to a database or other source for this information (leveraging Spring capabilities to do so robustly). The FilmService class provides methods to add a film to the list and to get the list of films.

Testing our REST API

Now that our webservice is ready we can run our application by right-clicking on our project, selecting “Run As…” -> “Spring Boot App”. The embedded tomcat server will be launched and the webservice will be deployed. Now we can access the web-service by pointing our browser at http://localhost:8080/films or by using Postman.

When a GET request is sent the URL http://localhost:8080/films for the first time, the server responds with the empty list. This is because the collection is initialised empty. Sending a POST request to the same URL with a JSON object having the details of a film adds it to the database. After the POST request is successful (indicated by a 201 response code), a subsequent GET request returns a list with all the films added. Multiple such POST requests can be made to add more films to the database. Below is some sample JSON data for testing the webservice.

One more thing to notice: When the server returns the list of films, it returns the genre attribute as a string although it stores it internally as an enum. This is done to represent the object using JSON. The webservice also accepts string for this field and internally converts it into the enum. Thus, client and server exchange a representation of the resource — not the resource itself.

Implementing PUT and DELETE operations

Now that we can add new films get the updated list, let’s add the ability to modify films in the database. We extend the FilmService & FilmController with methods to update and remove films. The updated source for the FilmService class is below.

We have 2 new methods – one to update an existing entry and the other to delete. Both these methods throw an IllegalArgumentException if the id cannot be found in the database.

The updated source for the FilmController class is below.

We have added 2 new methods. The first one is update() – the @PUT decorator indicates that this method handles PUT requests. The @Path & @Consumes decorations specify, respectively, the resource path and data-type accepted. This method delegates to the fs.updateFilm method and returns the updated Film object back.

Next we have the delete method having the @DELETE decorator which removes the film and returns OK if that is successful.

Handling Exceptions

To handle the exceptions that the methods of FilmService class may throw we create a generic ExceptionMapper class and register it as a provider. The source code for this class is below. This class simply returns a server error response built with the message from the exception.

Results

Now the REST API is complete and supports all the CRUD operations. We can test it using Postman and the test data given above.

rest service test

reset service test

Final remarks

As you can see from this post, it is very easy to create RESTFul web-services in Java using STS and Jersey. Combining Jersey which is the reference JAX-RS implementation with Spring allows us to leverage both the frameworks and focus development efforts purely on the business logic leaving out the rest of the details to be handled by the frameworks.

Hope you enjoyed learning this and given the popularity of REST APIs, I hope you can apply it in your life.

Leave a Reply