REST is an architectural style for implementing web services over standard HTTP. You can learn more about REST from the following resources:html Building Web Services the REST Wayjava Introduction to REST Slide Deckweb REST Tutorialexpress How to Create a REST Protocolcanvas RESTful Web Services bookrestful Second Generation Web Servicesapp Java API for RESTful Web ServicesThe JAX-RS (Java API for RESTful Web Services) specification presented in JSR 311 defines a standard way to deploy RESTful web services using annotated POJOs (plain old Java objects). For detailed information, you can read the JSR here. In this article, we'll use JAX-RS to create a simple sample application that allows you to add, retrieve, and delete books from a virtual library.this
Design the REST APIThe first thing to do when creating a new RESTful web service is to define an API that exposes service functionality to the web service client. REST is often called a Resource Oriented Architecture (ROA) since it is based on resources that are uniquely addressable via URIs (Uniform Resource Identifier). A REST API exposes the ability to perform a small set of operations on these resources. Essentially, there are four important elements within a REST service call that must be defined by the service author. These elements are as follows:
Let's take a closer look at each of these elements. HTTP MethodThe HTTP method indicates the type of action that should be taken on the resource specified by the URI. RESTful services typically use four methods that roughly equate the standard CRUD (create, read, update, delete) operations as follows:
The GET method is used for calls that have no side effects on the server (any calls that have no side effects should always use GET). An example of this would be when retrieving information about a book. No transaction is taking place so the book can be retrieved any number of times without altering state on the server. A typical GET method call looks like this: GET http://{server}/MyRestService/library/books/12345 Notice that the PUT and POST operations can both be used to create and update resources. This has been a cause of much confusion when creating REST services. Here is a hint from the bookRESTful Web Services to help you decide when to use each method:
Another way of stating this rule is to say that PUT should be used when creating a new URI and POST when calling an existing URI. So, you use PUT to create (as well as update) resources when the client controls the URI that references the resource. For example, the client can create a new book that is referenced by an ISBN number assigned by the client in this manner: PUT http://{server}/MyRestService/library/books/12345 Notice that the client passed the ID (12345) by which this book will be referenced. This call creates a new book resource that can be accessed as shown in the GET method above. In this case, the PUT operation is appropriate because the client is responsible for specifying the URI that uniquely identifies the book. On the other hand, consider a service call where the client doesn't specify the URI: POST http://{server}/MyRestService/library/books/12345/reviews This call creates a review for the specified book. In a case like this, the server will return the URI by which the review can be referenced in the GET http://{server}/MyRestService/library/books/12345/reviews/2937846292 In this case, the new review resource is known as a subordinate resource. A subordinate resource is a resource that only exists in relation to some parent resource. In other words, a review cannot exist on its own without being attached to a book. POST is usually used for creating subordinate resources. PUT and POST can both be used for updating resources but PUT replaces the entire resource while POST may update only a portion of it. For example, if the PUT request shown above is called a second time with a different book representation, the entire book with ID 12345 will be replaced with the new representation. In order to update just a portion of the resource using PUT, you would need to create a new subordinate resource. For example, if the book had a "checkedOut" property, we could use PUT to set this property by defining a new resource at this URL: PUT http://{server}/MyRestService/library/books/12345/checkedOut This new resource would allow you to update just one property of book 12345 using PUT (since it is replacing the entire checkedOut resource). POST could also be used to modify book 12345 without the new resource (often called an "overloaded POST") but that approach isn't as true to REST principles. Note that PUT is idempotent while POST is not. Idempotent means that the operation can be safely performed multiple times. Consider how performing the same PUT operation multiple times does not change the server state (since subsequent PUT requests would simply replace the original resource with an identical representation). POST, on the other hand, is not idempotent because it creates a new resource with each call. Performing multiple identical POST operations causes the server state to change with every execution (as a new resource is created each time). These are the key differences between the PUT and POST methods. Hopefully these general rules will help you when choosing which method to use in your REST service. Finally, the DELETE method is used to delete resources. Like PUT, DELETE is idempotent and it operates on an entire resource. That is, the whole resource is must be deleted rather than just a part of it. A typical DELETE method call looks like this: DELETE http://{server}/MyRestService/library/books/12345 After deleting a resource, it is no longer available. In this case, issuing a GET request to this resource would return an HTTP status code of 404 (Not Found). URIThe URIs by which resources are referenced are an important part of the REST API. One of the most fundamental REST principles is that URIs should represent nouns, not verbs. There are two good reasons for this. First, the actions that can be performed have already been defined by the HTTP protocol (GET, POST, PUT, DELETE). We should not be defining new actions through naming resources using verbs. Second, since REST requires us to specify an action based on the standard HTTP methods with each call, it only makes sense that this action would be performed against a concrete resource (noun) as opposed to another action (verb). For example, consider the following URI: GET http://{server}/MyRestService/library/getBooks In essence, this URI is saying "get the getBooks resource". This is redundant and a bit confusing. A better way to express this idea is through a URI like this: GET http://{server}/MyRestService/library/books This URI just says "get the books resource". The representation of the books resource would naturally be a list of books stored in the library. Another common guideline is to use plural nouns for collections of items and perform actions against this collection. For example, consider the following service calls:
Notice how the last GET operation and the DELETE operation referenced an individual book through the books collection. This conveys the idea that we are retrieving a single book from the collection of all books. The URIs for REST services will typically grow in a hierarchical fashion. For example, imagine that our library service allowed patrons to attach a review to each book. To accommodate this use case, the URI for this service should first reference the book to which the review applies and then the review itself in this manner: GET http://{server}/MyRestService/library/books/12345/reviews/1 To get a list of all reviews pertaining to the book identified by ISBN 12345, we could use a URI like this: GET http://{server}/MyRestService/library/books/12345/reviews Request BodyMost REST service calls do not contain any information in the body of the request. This is due to the fact that the HTTP header often includes all the information needed to invoke a service. The HTTP header includes the HTTP method, URI, and all HTTP header fields. In fact, certain HTTP methods, such as GET and DELETE, do not support any data in the body of the request at all. However, HTTP methods that create or modify resources, such as POST and PUT, should include the information necessary to perform that action. For instance, a PUT operation by definition should always include a full representation of the resource being created or replaced. On the other hand, a POST operation may include just enough information required by the service to create or update a resource. The important thing to know about the request body is that it is unique to each service. The service designer must define the format of the request body and convey that to service consumers. Information in the request body is typically encoded in XML or JSON format. Here is a typical HTTP request that contains XML information within the body: POST http://www.sourcestream.com/books HTTP/1.1 The sample HTTP request above indicates that the client is creating a new book by performing a POST to the books resource. The Content-Type header indicates that the request body is formatted in XML. ResponseThe response to a REST service call contains various information of interest to the client. To begin, a REST response always includes a status code that conveys the result of the requested operation. The available status codes are defined by the HTTP specification and are grouped into 5 ranges that convey a general meaning. These five ranges are as follows:
Here are some of the most common response status codes:
In addition to the status code, the response may contain a Content-Type header. This header indicates the type of content contained in the body of the response (e.g., image, XML, JSON, etc.). To illustrate, here is a typical HTTP response that uses the Content-Type header to indicate that the body of the response is in XML format: HTTP/1.1 200 OK In response to a GET request, a representation of the requested resource is returned to the client. Similar to the request body, the format of this representation is service-specific. The service consumer must refer to documentation provided by the service provider in order to determine how the body of the response is to be interpreted. Some REST service calls may not return anything within the body of the message. For example, in response to a POST request to create a new resource, the service will typically just respond with a message indicating that the resource was requested and the location of the new resource as illustrated here: HTTP/1.1 201 Created The response above indicates that a new book resource was successfully created and is available at the URI indicated by the Location header. Document the REST APINow that you understand the different parts of a REST service's request and response, you're ready to define an API that will be exposed to service consumers. It is recommended to begin by defining the different parts (nouns) in the system and then determine which of the HTTP actions need to be performed on each. For instance, in the library example presented earlier, there are two objects that can be acted on: books and reviews. We can consider these two objects as the resources upon which REST service clients will be acting. The operations that we implement will be determined by the use cases that the service must support. For instance, the user should be able to create, read, update, and delete both books and reviews. This means that we'll implement support for GET, PUT or POST, and DELETE for each resource. Here is a list of operations that the library service will support:
Another common way to document a REST API is to use a table showing the available REST actions across the top and the resources upon which actions are performed on the left like this:
Create the REST ServiceWe will now create a REST service that allows the user to create, retrieve, update, and delete books from a library. Adding support for book reviews as shown in the REST API is an exercise that is left to the reader. JAX-RS makes creating a RESTful web services very simple. Start by annotating a class with path information that maps a request's URI to the class that should process the request. For example, consider the following class: @Path("/library") The GET http://{server}/MyRestService/library/books Note that the path information begins immediately following the web application's context name. In this case, the application's context name is MyRestService. Create the GET MethodsAfter creating an annotated class, we are ready to create methods to return information to the web service client. We'll start by defining two methods that return information about the books available to the library service. @GET Now let's examine these two methods in detail. The first method, getBooks(), indicates that it should be called in response to an HTTP GET (note the The next method, getBook(), is a little more complex. From the annotations on this method we can see that it is called to process HTTP GET requests to the In addition to the path portion of the URI, you can also inject values from the query string into a method parameter like this: @GET Therefore, given a URI like Create the PUT MethodThe next method we'll create will allow the client to add or update a book. In this case, the same method supports both add and update because it processes PUT requests. Remember that PUT requests either create or replace a resource. Therefore, the method implementation is often very similar, if not identical. This is due to the fact that either operation may simply require the implementation to create a resource and add it to a collection. If the resource already existed, it is overwritten. If not, the new resource is added. Here's the definition for the create/update method: @PUT This method is very similar to getBooks() except that it processes PUT requests rather than GET. Note that the value following Notice that this method returns a if (books.containsKey(isbn)) As you can see, if the book that was passed already existed, the response status code is set to 200 (OK). If the book did not exist previously, the status code is set to 201 (Created). See the full implementation at Library REST Sample or in the sample project presented below for more information. Create the DELETE MethodLast we'll create the method that allows the client to delete books from the library. The definition for this method looks like this: @DELETE From this definition, we can see that this method process HTTP DELETE methods (based on the
Create a Test ApplicationThe RestEasy implementation of JAX-RS includes a client library that makes creating REST clients quick and easy. The client library is easy to learn because it uses the same JAX-RS annotations as the REST service except their meaning is reversed. For example, the Client InterfaceTo create a RestEasy client application, start by creating an interface that describes the remote services that you'd like to call. Let's look at a simple example: import javax.ws.rs.*; The annotations in this example work similarly to the way they do in a service class. The The The ClientResponse<String> response = client.createReview("12345", "<Review>Great book!</Review>"); As you would expect, this call will generate a POST request to the Now let's look at the Finally, let's look at the return type. You may have noticed that the return type for ClientResponse<String> response = client.createReview("12345", "<Review>Great book!</Review>"); Last, let's briefly examine the Response.Status status = client.deleteBook("12345"); Also notice that the Client ApplicationNow that we have a REST client interface defined, let's create an application that uses it to test our REST service. The RestEasy client library uses a Java mechanism known as a dynamic proxy to construct a concrete instance of our interface according to the annotations we defined. It seems a little like magic but, fortunately, we don't have to worry about how the import org.resteasy.spi.ResteasyProviderFactory; The first two lines in the
Create a Test HTML PageOne advantage of REST services over SOAP is that they can be tested from a simple HTML page within a browser. A page like this is usually placed in the root of the REST web service application and named something like
Let's take a look at how this an HTML page is created to test each of the methods supported by the sample REST service. Get BooksAs documented above, the get books REST service call looks like this: GET http://<server>/<context>/library/books Since hyperlinks always use the HTTP GET method, this service call is easily made available by one line in an HTML page: <a href="library/books">Get All Books</a> For instance, if the above line was stored in a file named
Where Get BookThe HTML to test the "Get Book" functionality is slightly more complex because the user must be prompted for the ISBN of the book to retrieve. To accomplish this, we'll need to use an HTML form, input box, button, and a little JavaScript to collect and submit the information to the REST service. The HTML for this feature looks like this: <form name="GetBook" method="GET"> You might be wondering why the JavaScript is necessary in the button's GET http://localhost/<context>/library/books?isbn=12345 Unfortunately, this is not the format defined by the "get book" REST service. Rather, the isbn number should be part of the path. To accomplish this, the JavaScript sets the form's Add or Update BookThe "add or update book" REST service is a bit trickier to test since it uses the HTTP PUT method. Unfortunately, PUT (as well as DELETE) is not supported by standard HTML. Contrast that with GET and POST which are both natively supported by HTML forms and are easily implemented by setting the form's So, how can we test PUT and DELETE service calls from an HTML page? In a word, the answer is JavaScript. JavaScript allows us to make Ajax requests that support all HTTP methods. Let's see how this is done in the HTML: <form name="AddUpdateBook"> In the HTML above, we collect the information on a book to be added or updated using standard HTML form elements. However, rather than submitting the form as usual, we make a call to a JavaScript method called function addUpdateBook(isbn, title) We won't go into too much detail about Ajax programming but notice how this JavaScript invokes a PUT request to the You might be wondering about that mysterious function getXmlHttp() Delete BookAs mentioned in the previous section, the HTTP DELETE method is not supported by standard HTML so we must resort to JavaScript in order to make DELETE requests. The HTML portion of the DELETE test looks like this: <form name="DeleteBook"> Similar to the "Add or Update Book" function, the "Delete Book" feature prompts the user for the ISBN of the book to delete and passes it to the function deleteBook(isbn) Similar to the
Sample ProjectThe sample project uses JBoss's RestEasy implementation of JAX-RS. RestEasy is deployed as a standard JEE web application. To define a new service, simply drop a new JAX-RS annotated class into the RestEasy web application's Follow these steps to try out the sample REST service presented in this article:
|