16 min read

Representational State Transfer

Representational State Transfer (REST) is a style of information application architecture that aligns the distributed applications to the HTTP request and response protocols, in particular matching Hypermedia to the HTTP request methods and Uniform Resource Identifiers (URI).

Hypermedia is the term that describes the ability of a system to deliver self-referential content, where related contextual links point to downloadable or stream-able digital media, such as photographs, movies, documents, and other data. Modern systems, especially web applications, demonstrate through display of text that a certain fragment of text is a link to the media.

Hypermedia is the logical extension of the term hypertext, which is a text that contains embedded references to other text. These embedded references are called links, and they immediately transfer the user to the other text when they are invoked. Hypermedia is a property of media, including hypertext, to immediately link other media and text.

In HTML, the anchor tag <a> accepts a href attribute, the so-called hyperlink parameter.

The World Wide Web is built on the HTTP standards, Versions 1.0 and 1.1, which define specific enumerations to retrieve data from a web resource. These operations, sometimes called Web Methods, are GET, POST, PUT, and DELETE. Representational State Transfer also reuses these operations to form semantic interface to a URI.

Representational State Transfer, then, is both a style and architecture for building network enabled distributed applications. It is governed by the following constraints:

  • Client/Server: A REST application encourages the architectural robust principle of separation of concerns by dividing the solution into clients and servers. A standalone, therefore, cannot be a RESTful application. This constraint ensures the distributed nature of RESTful applications over the network.
  • Stateless: A REST application exhibits stateless communication. Clients cannot and should not take advantage of any stored context information in the server and therefore the full data of each request must be sent to the server for processing.
  • Cache: A REST application is able to declare which data is cacheable or not cacheable. This constraint allows the architect to set the performance level for the solution, in other words, a trade-off. Caching data to the web resource, allows the business to achieve a sense of latency, scalability, and availability. The counter point to improved performance through caching data is the issue of expiration of the cache at the correct time and sequence, when do we delete stale data? The cache constraint also permits successful implementation providers to develop optimal frameworks and servers.
  • Uniform Interface: A REST application emphasizes and maintains a unique identifier for each component and there are a set of protocols for accessing data. The constraint allows general interaction to any REST component and therefore anyone or anything can manipulate a REST component to access data. The drawback is the Uniform Interface may be suboptimal in ease-of-use and cognitive load to directly provide a data structure and remote procedure function call.
  • Layered Style: A REST application can be composed of functional processing layers in order to simplify complex flows of data between clients and servers. Layered style constraint permits modularization of function with the data and in itself is another sufficient example of separation of concerns. The layered style is an approach that benefits load-balancing servers, caching content, and scalability.
  • Code-on-Demand: A REST application can optimally supply downloadable code on demand for the client to execute. The code could be the byte-codes from the JVM, such as a Java Applet, or JavaFX WebStart application, or it could be a JavaScript code with say JSON data. Downloadable code is definitely a clear security risk that means that the solution architect must assume responsibility of sandboxing Java classes, profiling data, and applying certificate signing in all instances. Therefore, code-on-demand, is a disadvantage in a public domain service, and this constraint in REST application is only seen inside the firewalls of corporations.

In terms of the Java platform, the Java EE standard covers REST applications through the specification JAX-RS and this article covers Version 2.0.

JAX-RS 2.0 features

For Java EE 7, the JAX-RS 2.0 specification has the following new features:

  • Client-side API for invoking RESTful server-side remote endpoint
  • Support for Hypermedia linkage
  • Tighter integration with the Bean Validation framework
  • Asynchronous API for both server and client-side invocations
  • Container filters on the server side for processing incoming requests and outbound responses
  • Client filter on the client side for processing outgoing request and incoming responses
  • Reader and writer interceptors to handle specific content types

Architectural style

The REST style is simply a Uniform Resource Identifier and the application of the HTTP request methods, which invokes resources that generate a HTTP response. Although Fielding, himself, says that REST does not necessarily require the HTTP communication as a networker layer, and the style of architecture can be built on any other network protocol.

Let’s look at those methods again with a fictional URL (http://fizzbuzz.com/)

Method

Description

POST

A REST style application creates or inserts an entity with the supplied data. The client can assume new data has been inserted into the underlying backend database and the server returns a new URI to reference the data.

PUT

A REST style application replaces the entity into the database with the supplied data.

GET

A REST style application retrieves the entity associated with the URI, and it can be a collection of URI representing entities or it can be the actual properties of the entity

DELETE

A REST style application deletes the entity associated with the URI from the backend database.

The user should note that PUT and DELETE are idempotent operations, meaning they can be repeated endlessly and the result is the same in steady state conditions.

The GET operation is a safe operation; it has no side effects to the server-side data.

REST style for collections of entities

Let’s take a real example with the URL http://fizzbuzz.com/resources/, which represents the URI of a collection of resources. Resources could be anything, such as books, products, or cast iron widgets.

Method

Description

GET

Retrieves the collection entities by URI under the link http://fizzbuzz.com/resources and they may include other more data.

POST

Creates a new entity in the collection under the URI http://fizzbuzz.com/resources. The URI is automatically assigned and returned by this service call, which could be something like http://fizzbuzz.com/resources/WKT54321.

PUT

Replaces the entire collection of entities under the URI http://fizzbuzz.com/resources.

DELETE

Deletes the entire collection of entities under the URI http://fizzbuzz.com/resources.

As a reminder, a URI is a series of characters that identifies a particular resource on the World Wide Web. A URI, then, allows different clients to uniquely identify a resource on the web, or a representation. A URI is combination of a Uniform Resource Name (URN) and a Uniform Resource Locator (URL). You can think of a URN like a person’s name, as way of naming an individual and a URL is similar to a person’s home address, which is the way to go and visit them sometime.

In the modern world, non-technical people are accustomed to desktop web browsing as URL. However, the web URL is a special case of a generalized URI.

A diagram that illustrates HTML5 RESTful communication between a JAX RS 2.0 client and server, is as follows:

REST style for single entities

Assuming we have a URI reference to a single entity like http://fizzbuzz.com/resources/WKT54321.

Method

Description

GET

Retrieves the entity with reference to URI under the link http://fizzbuzz.com/resources/WKT54321.

POST

Creates a new sub entity under the URI http://fizzbuzz.com/resources/WKT54321. There is a subtle difference here, as this call does something else. It is not often used, except to create Master-Detail records. The URI of the subentity is automatically assigned and returned by this service call, which could be something like http://fizzbuzz.com/resources/WKT54321/D1023

PUT

Replaces the referenced entity’s entire collection with the URI http://fizzbuzz.com/resources/WKT54321 . If the entity does not exist then the service creates it.

DELETE

Deletes the entity under the URI references http://fizzbuzz.com/resources/WKT54321

Now that we understand the REST style we can move on to the JAX-RS API properly.

Consider carefully your REST hierarchy of resources

The key to build a REST application is to target the users of the application instead of blindly converting the business domain into an exposed middleware. Does the user need the whole detail of every object and responsibility in the application? On the other hand is the design not spreading enough information for the intended audience to do their work?

Servlet mapping

In order to enable JAX-RS in a Java EE application the developer must set up the configuration in the web deployment descriptor file. JAX-RS requires a specific servlet mapping to be enabled, which triggers the provider to search for annotated classes.

The standard API for JAX-RS lies in the Java package javax.ws.rs and in its subpackages. Interestingly, the Java API for REST style interfaces sits underneath the Java Web Services package javax.ws.

For your web applications, you must configure a Java servlet with just fully qualified name of the class javax.ws.rs.core.Application. The Servlet must be mapped to a root URL pattern in order to intercept REST style requests.

The following is an example code of such a configuration:

<?xml version="1.0" encoding="UTF-8"?>
<web-app

xsi:schemaLocation="http://
metadata-complete="false">
<display-name>JavaEE Handbook 7 JAX RS Basic
</display-name>
<servlet>
<servlet-name>javax.ws.rs.core.Application
</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application
</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>

In the web deployment descriptor we just saw, only the servlet name is defined, javax.ws.rs.core.Application. Do not define the servlet class. The second step maps the URL pattern to the REST endpoint path. In this example, any URL that matches the simplified Glob pattern /rest/* is mapped. This is known as the application path.

A JAX-RS application is normally packaged up as a WAR file and deployed to a Java EE application server or a servlet container that conforms to the Web Profile. The application classes are stored in the /WEB-INF/classes and required libraries are found under /WEB-INF/lib folder. Therefore, JAX-RS applications share the consistency of configurations as servlet applications.

The JAX-RS specification does recommend, but does not enforce, that conformant providers follow the general principles of Servlet 3.0 plug-ability and discoverability of REST style endpoints. Discoverability is achieved in the recommendation through class scanning of the WAR file, and it is up to the provider to make this feature available.

An application can create a subclass of the javax.ws.rs.core.Application class. The Application class is a concrete class and looks like the following code:

public class Application {
public Application() { /* ... */ }
public java.util.Set<Class<?>> getClasses() {
/* ... */ }
public java.util.Set<Object> getSingletons() {
/* ... */ }
public java.util.Map<String,Object> getProperties() {
/* ... */ }
}

Implementing a custom Application subclass is a special case of providing maximum control of RESTful services for your business application. The developer must provide a set collection of classes that represent JAX-RS end points. The engineer must supply a list of Singleton object, if any, and do something useful with the properties.

The default implementation of javax.ws.rs.core.Application and the methods getClasses() and getSingletons() return empty sets. The getProperties() method returns an empty map collection. By returning empty sets, the provider assumes that all relevant JAX-RS resource and provider classes that are scanned and found will be added to the JAX-RS application.

Majority of the time, I suspect, you, the developer will want to rely on annotations to specify the REST end points and there are Servlet Context listeners and Servlet Filters to configure application wide behavior, for example the startup sequence of a web application.

So how can we register our own custom Application subclass? The answer is just subclass the core class with your own class.

The following code explains what we just read:

package com.fizbuzz.services;
@javax.ws.rs.ApplicationPath("rest")
public class GreatApp extends javax.ws.rs.core.Application {
// Do your custom thing here
}

In the custom GreatApp class, you can now configure logic for initialization. Note the use of @ApplicationPath annotation to configure the REST style URL. You still have to associate your custom Application subclass into the web deployment descriptor with a XML Servlet name definition.

Remember the Application Configuration

A very common error for first time JAX-RS developers is to forget that the web deployment descriptor really requires a servlet mapping to a javax.ws.js.core.Application type.

Now that we know how to initialize a JAX-RS application, let us dig deeper and look at the defining REST style endpoints.

Mapping JAX-RS resources

JAX-RS resources are configured through the resource path, which suffixes the application path. Here is the constitution of the URL.

http://<hostname>:<port>/<web_context>/<application_path>/<resource_path>

The <hostname> is the host name of the server. The <port> refers to the port number, which is optional and the default port is 80. The <web_context> is the Servlet context, which is the context for the deployed web application. The <application_path> is the configuration URI pattern as specified in the web deployment descriptor @ApplicationPath or the Servlet configuration of Application type. The <resource_path> is the resource path to REST style resource.

The final fragment <resource_path> defines the URL pattern that maps a REST style resource. The resource path is configured by annotation javax.ws.rs.Path.

Test-Driven Development with JAX-RS

Let us write a unit test to verify the simplest JAX-RS service. It follows a REST style resource around a list of books. There are only four books in this endpoint and the only thing the user/client can do at the start is to access the list of books by author and title. The client invokes the REST style endpoint, otherwise known as a resource with an HTTP GET request.

The following is the code for the class RestfulBookService:

package je7hb.jaxrs.basic;
import javax.annotation.*;
import javax.ws.rs.*;
import java.util.*;
@Path("/books")
public class RestfulBookService {
private List<Book> products = Arrays.asList(
new Book("Sir Arthur Dolan Coyle",
"Sherlock Holmes and the Hounds of the Baskervilles"),
new Book("Dan Brown", "Da Vinci Code"),
new Book("Charles Dickens", "Great Expectations"),
new Book("Robert Louis Stevenson", "Treasure Island"));
@GET
@Produces("text/plain")
public String getList() {
StringBuffer buf = new StringBuffer();
for (Book b: products) {
buf.append(b.title); buf.append('n'); }
return buf.toString();
}
@PostConstruct
public void acquireResource() { /* ... */ }
@PreDestroy
public void releaseResource() { /* ... */ }
static class Book {
public final String author;
public final String title;
Book(String author, String title) {
this.author = author;
this.title = title;
}
}
}

The annotation @javax.ws.rs.Path declares the class as a REST style end-point for a resource. The @Path annotation is assigned to the class itself. The path argument defines the relative URL pattern for this resource, namely/books.

The method getList() is the interesting one. It is annotated with both @javax.ws.rs.GET and @javax.ws.rs.Produces.

The @GET is one of the six annotations that conform to the HTTP web request methods. It indicates that the method is associated with HTTP GET protocol request.

The @Produces annotation indicates the MIME content that this resource will generate. In this example, the MIME content is text/plain.

The other methods on the resource bring CDI into the picture. In the example, we are injecting post construction and pre destruction methods into the bean.

This is the only class that we require for a simple REST style application from the server side. With an invoking of the web resource with a HTTP GET Request like http://localhost:8080/mywebapp/rest/books we should get a plain text output with list of titles like the following:

Sherlock Holmes and the Hounds of the Baskervilles
Da Vinci Code
Great Expectations
Treasure Island

So do we test this REST style interface then? We could use Arquillian Framework directly, but this means our tests have to be built specifically in a project and it complicates the build process. Arquillian uses another open source project in the JBoss repository called ShrinkWrap. The framework allows the construction of various types of virtual Java archives in a programmatic fashion.

Let’s look at the unit test class RestfulBookServiceTest in the following code:

package je7hb.jaxrs.basic;
// import omitted
public class RestfulBookServiceTest {
@Test
public void shouldAssembleAndRetrieveBookList()
throws Exception {
WebArchive webArchive =
ShrinkWrap.create(WebArchive.class, "test.war")
.addClasses(RestfulBookService.class)
.setWebXML(
new File("src/main/webapp/WEB-INF/web.xml"))
.addAsWebInfResource(
EmptyAsset.INSTANCE, "beans.xml");
File warFile = new File(webArchive.getName());
new ZipExporterImpl(webArchive)
.exportTo(warFile, true);
SimpleEmbeddedRunner runner =
SimpleEmbeddedRunner.launchDeployWarFile(
warFile, "mywebapp", 8080);
try {
URL url = new URL(
"http://localhost:8080/mywebapp/rest/books");
InputStream inputStream = url.openStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream));
List<String> lines = new ArrayList<>();
String text = null;
int count=0;
while ( ( text = reader.readLine()) != null ) {
lines.add(text);
++count;
System.out.printf("**** OUTPUT ****
text[%d] = %sn", count, text );
}
assertFalse( lines.isEmpty() );
assertEquals("Sherlock Holmes and the Hounds
of the Baskervilles", lines.get(0));
assertEquals("Da Vinci Code", lines.get(1));
assertEquals("Great Expectations", lines.get(2));
assertEquals( "Treasure Island", lines.get(3) );
}
finally {
runner.stop();
}
}
}

In the unit test method, shouldAssembleAndRetrieveBookList(), we first assemble a virtual web archive with an explicit name test.war. The WAR file contains the RestfulBookService services, the Web deployment descriptor file web.xml and an empty beans.xml file, which if you remember is only there to trigger the CDI container into life for this web application.

With the virtual web archive, we export the WAR as a physical file with the utility ZipExporterImpl class from ShinkWrap library, which creates the file test.war in the project root folder.

Next, we fire up the SimpleEmbeddedRunner utility. It deploys the web archive to an embedded GlassFish container. Essentially, this is the boilerplate to get to deliver a test result.

We, then, get to the heart of the test itself; we construct a URL to invoke the REST style endpoint, which is http://localhost:8080/mywebapp/rest/books. We read the output from the service endpoint with Java standard I/O line by line into a list collection of Strings. Once we have a list of collections, then we assert each line against the expected output from the rest style service.

Because we acquired an expensive resource, like an embedded Glassfish container, we are careful to release it, which is the reason, why we surround critical code with a try-finally block statement. When the execution comes to end of test method, we ensure the embedded GlassFish container is shut down.

LEAVE A REPLY

Please enter your comment!
Please enter your name here