Web Services are nothing than Services provided by the server over the Web in the form of some APIs. These APIs are leveraged to get Server resources through Java code. Similar to a normal Client/Server model, the Client makes an HTTP request to the server and, in turn, the Server returns an HTTP response. The difference between the normal Client/Server communication model and a Web Service is that the supposed consumer of the information of the former is a human. As a result, a lot of attention is given to the presentation of information. Web Service responses, on the other hand, are not a not meant for human consumption, at least directly. APIs provide programmatic access to the server resources. How the resources received by the Web services will be presented to the human client is not at all a concern here, because the direct consumer endpoint of the resource is often a Java application. The application, such as Facebook, Twitter, Amazon, and so forth, publishes Web service APIs to get programmatic access of the resources so that developers can build upon it by using those APIs. The article digs into some of the key aspects to get started and will take it further in the next article.
Web Services
There are two standard ways to implement web services in Java. One is via SOAP; another is via RESTful. SOAP is a protocol based, as the name suggests, on the Simple Object Access Protocol (SOAP). The rules are very strict, backed by some stern specification keepers. Any SOAP Web service implementation must follow these standards that are vehemently laid down by the specification. a RESTful Web service, on the other hand, has no such rules; it’s not even a protocol or a standards; it’s a free bird, a concept to build upon. It is not even a Web service, per se, but an architectural standard. The term REpresentational State Transfer (REST) was coined by Roy Fielding in this doctoral thesis. The simplicity of its implementation is the key point that garnered attention of technological enthusiasts. Anything built upon following these guidelines is RESTful. Thus, if a Web service is build according to these guidelines, it is a RESTful web service. It’s just that simple.
The Working Principle Behind RESTful Web Services
The principle that works behind fetching RESTful Web service resources is through an HTTP URL. To put it in a simple manner, suppose we want a list of items available from a Web site, say abc.org. We may write the URL as http://abc.org/service/items and suppose if we want the list of a specific item, we may write the URL as http://abc.org/service/items/specifitem. How simple is that!
A Java client conveys method information through HTTP methods. The common HTTP methods are GET, PUT, POST, and DELETE. There are other methods such as HEAD, LINK, OPTIONS, VIEW, and so on; however, GET, PUT, POST, and DELETE are the most common.
- GET is used to retrieve resource data,
- POST creates a new resource from the requested data,
- PUT updates a resource from the requested data, and
- DELETE removes the resource.
These four methods correspond to familiar CRUD operations of computing. Jersey, or JAX-RS, provides annotation APIs with the same name to mark any method of appropriate action. Thus, the action information goes into HTTP methods while the scoping information goes into URI. At the consumer endpoint, resources are obtained generally in the format of plain text, XML, or JSON. It can be any other format; there is no specific rule for that, provided an appropriate converter is used to convert the raw information into the chosen format. The client who receives information must be able to parse it out of the format. In the case of XML, there is no problem because Java comes with the JAXB library that can parse XML. But, there is no such support for JSON from Java; hence, an external library is required. In a similar manner, if other formats are used, they need an appropriate parser to be included during implementation; otherwise, the Java compiler will throw exceptions and error messages during compilation.
Where Does Jersey Fit In?
Well, Jersey is a library like any other Java library and fits into the same band where other libraries fit in a Java application. This library makes our life easy while programming RESTful Web services. It is simply an implementation of the JAX-RS specification. We can absolutely create RESTful Web services without any third-party intervention, but that would be like reinventing wheels every time we want to build a car. Now, who wants to do that? Jersey, however, is not the only library in the genre; there are others as well. Because all of them follow the JAX-RS specification, pick any one; the APIs are all the same. Jersey is a widely used library hardened by time though bugs may creep up once a while, yet it is reliable and can be downloaded from the Jersey site in a zipped bundle. The latest stable release version 2.21 of Jersey (as of writing this article) does not provide jars required for JSON; hence, to meet the dependencies they must be hunted down. Good luck! if you seek to embark on a mission, consider jar file versions very closely because there are issues of incompatibility and missing APIs.
A friendly suggestion: When working with Jersey, it is better to use it via Maven as suggested in the download section of the Jersey site unless you are ready to go through the hell of hunting down all the jar dependencies augmented by the kaleidoscope of up- and down-grading versions of jar files to keep the compatibility. The Java compiler has a very loud mouth that often spikes even through the double cushioned patience pad. I am mostly perforated and sieved due to my inherent lunacy of walking untrodden ways; in short, do not go the way I go and let pom.xml created by Maven do its job and have a happy coding experience rather than happy hunting :).
What Do You Need to Get Started?
To begin with, following are the jar requirements (see Figure 1) apart from Tomcat 7 application server, JDK, and Eclipse IDE. They can be separately downloaded or use a jersey-quickstart-webapp Maven archetypes project template in Eclipse. Maven automatically downloads the required dependencies and provides a project structure to build upon. Here, we shall create a simple application demonstrating how to create RESTful Web services application in Java.
Figure 1: Jersey jar dependency files
The contents of the pom.xml files are as follows:
<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>org.mano.restdemo</groupId> <artifactId>doctorszone</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>doctorszone</name> <build> <finalName>doctorszone</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.5.1</version> <inherited>true</inherited> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> <dependencyManagement> <dependencies> <dependency> <groupId>org.glassfish.jersey</groupId> <artifactId>jersey-bom</artifactId> <version>${jersey.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet-core</artifactId> <!-- use the following artifactId if you don't need <!-- servlet 2.x compatibility <!-- artifactId>jersey-container-servlet</artifactId --> </dependency> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-moxy</artifactId> </dependency> </dependencies> <properties> <jersey.version>2.17</jersey.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project>
The contents of web.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?> <!-- This web.xml file is not required when using <!-- Servlet 3.0 container, <!-- see implementation details http://jersey.java.net/nonav/ <!-- documentation/latest/jax-rs.html --> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance" xsi_schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class >org.glassfish.jersey.servlet.ServletContainer </servlet-class> <init-param> <param-name> jersey.config.server.provider.packages </param-name> <param-value> org.mano.restdemo.doctorszone </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Jersey Web Application</servlet-name> <url-pattern>/webapi/*</url-pattern> </servlet-mapping> </web-app>
The model class:
package org.mano.restdemo.doctorszone.model; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Doctor { private long id; private String firstName; private String lastName; private String specializeIn; public Doctor() { super(); } public Doctor(long id, String firstName, String lastName, String specializeIn) { super(); this.id = id; this.firstName = firstName; this.lastName = lastName; this.specializeIn = specializeIn; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getSpecializeIn() { return specializeIn; } public void setSpecializeIn(String specializeIn) { this.specializeIn = specializeIn; } }
The Resource class:
package org.mano.restdemo.doctorszone.resources; 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 org.mano.restdemo.doctorszone .model.Doctor; import org.mano.restdemo.doctorszone .service.DoctorService; @Path("/doctors") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public class DoctorResource { DoctorService doctorService=new DoctorService(); @GET public List<Doctor> getDoctors(){ return doctorService.getAllDoctors(); } @GET @Path("/{doctorId}") public Doctor getDoctor(@PathParam("doctorId") long id){ return doctorService.getDoctor(id); } @POST public Doctor addDoctor(Doctor doc){ return doctorService.addDoctor(doc); } @PUT @Path("/{doctorId}") public Doctor updateDoctor(@PathParam("doctorId") long id, Doctor doc){ doc.setId(id); return doctorService.updateDoctor(doc); } @DELETE @Path("/{doctorId}") public void removeDoctor(@PathParam("doctorId") long id){ doctorService.removeDoctor(doctorService.getDoctor(id)); } }
The Service class with some dummy data:
package org.mano.restdemo.doctorscorner.service; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.mano.restdemo.doctorscorner.database.TestDatabase; import org.mano.restdemo.doctorscorner.model.Doctor; public class DoctorService { private Map<Long, Doctor> docs = TestDatabase.getDoctors(); public DoctorService(){ docs.put(1L, new Doctor(1L, "Amit", "Sharma", "Cardiac Surgeon")); docs.put(2L, new Doctor(2L, "Deepak", "Chopra", "Oncologist")); docs.put(3L, new Doctor(2L, "Sakshi", "Verma", "Neurologist")); docs.put(4L, new Doctor(2L, "Abhishek", "Tirki", "ENT")); docs.put(5L, new Doctor(2L, "Santanu", "Ahuja", "Dermatologist")); docs.put(6L, new Doctor(2L, "Binod", "Bansal", "Cardiac Surgeon")); docs.put(7L, new Doctor(2L, "Arup", "Sarkar", "Neurologist")); } public List<Doctor> getAllDoctors() { return new ArrayList<Doctor>(docs.values()); } public Doctor getDoctor(long id) { return docs.get(id); } public Doctor addDoctor(Doctor doc) { doc.setId(docs.size() + 1); docs.put(doc.getId(), doc); return doc; } public Doctor updateDoctor(Doctor doc) { if (doc.getId() <= 0) return null; docs.put(doc.getId(), doc); return doc; } public Doctor removeDoctor(Doctor doc) { return docs.remove(doc.getId()); } }
Database stub class:
package org.mano.restdemo.doctorscorner.database; import java.util.HashMap; import java.util.Map; import org.mano.restdemo.doctorscorner.model.Doctor; public class TestDatabase { private static Map<Long, Doctor> docs=new HashMap<>(); public static Map<Long, Doctor> getDoctors(){ return docs; } }
To test the application, a REST API client is required. There are many such REST API clients available. One of them is Postman; it can be freely downloaded as a Chrome extension from https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en.
Figure 2 shows the screen shot of resources obtained through a sGET request. For more information on Postman and how it works, refer to: https://www.getpostman.com/docs.
Figure 2: Resources obtained through a sGET request
Conclusion
The article demonstrates the application of REST APIs in Jersey with an emphasis on its implementation. This is, however, a tip of the iceberg. The next part of the article goes into more hands-on with examples further extending the use of other important features of Jersey/JAX-RS APIs.