CS639 Class 23  REST Services: more examples

 

paper handout of pg. 180 of RESTful Web Services, by Richardson and Ruby, showing URI templates for their bookmark service

 

orderService Software Architecture, Pull technology vs. notifications

 

So far we have been concentrating on orderServices REST services, since that’s what is important to clients, and also JAXB, which is more generally useful than just this one app.

 

Now look at it as a decent REST service implemention, and get ready for pa4, which expands it to handle payment and flexible options.

 

 

C:\CS\CS639\ORDERSERVICE\SRC

├───functionaltest

              ...

├───main

   └───java

       └───com

           └───restbucks

               └───ordering

                   ├───activities

                   ├───domain

                   ├───repositories

                   ├───representations

                   └───resources

└───test

... unit tests

 

orderService packages

resources: where the @GET, @POST, etc.,  handlers are for each resource. Minimal REST-related code is here.  The methods call into the main app code to do whatever the app is meant to do.

representations: where OrderRepresentation is, and any other POJO needed just for external communication.

domain: where Order is, also Item, used by both Order and OrderRepresentation, and the enums for all the options.  These are the POJOs used by the app internals in activities and repositories.

activities: the heart of the app. Implementations of the actions this app wants to do for each incoming request.  Also known as the “business layer” or “service layer”

repositories: code for accessing database tables or similar holders of long-term state for the app. Also known as the Data Access layer, or DAO layer, for data access objects.

 

Web apps (including orderService) generally have three layers:

·         Presentation layer: here resources: interacting with a user or external agents

·         Business/Service layer: here activities: the heart of the app, doing what it knows how to do

·         Data Access layer, here repositories: arranging long-term storage for app data

 

What is a layer here?

In a layered system, the code in a higher layer calls methods in the next layer down, or in its own layer, but never calls up to the layer above it.  Here resources methods call activities methods, and activities methods call repositories methods, which just do their thing saving or retrieving data and return.  Then the activities method returns to the resources method. 

 

That leaves domain as not being a layer.  That is correct: domain objects circulate in the system, carrying data.  After all, the data needs to flow from the network down into the long-term storage when an order is created, and back up when order status is asked for.

 

Note that the calls go down the layers even in the case that the data is coming up the layers.  Consider a GET for order status.

1.       It first shows up as a call into resources at the @GET method in OrderResource.

2.       This resources method calls into activities to get status by id.

3.       This activities method calls into repositories to get the data from long-term storage

4.       The data is returned from repositories to activities in an Order object.

5.       Then it is converted into an OrderRepresentation object and returned from activities  to resources

6.       Then in resources, the GET method of OrderResource sends it off as XML.

 

 

 

Pull Web Interactions

Note that the user has to ask over and over for status to be sure to find out immediately if their order is ready.  It would be nice if the system contacted the user when the order became ready.  But HTTP is client-request driven, otherwise known as Pull technology. Although the server’s web address is known to the client, and the server accepts new requests any time, the client does not have the same capability. The server gets to send to the client at the end of each client request, but once it closes that connection, it has lost contact.

 

In the case that the server must get back to the user at some “random” time, email is one option. That’s because the user has a relationship with another server, and checks it now and then, or has an email agent that periodically checks and signals new email. It is strightforward to add email capability to web apps, something like adding database access (covered in CS636).

 

Of course HTTP is not the only protocol on the network. It is possible to have a TCP connection open for longer times, say hours, and keep a conversation going between two ends. But in practice, it’s hard to engineer this approach, because the network has interruptions, and then you have to resynchronize the conversation. It’s better to live within the restrictions of HTTP.

 

Having only Pull Requests makes call-down layering possible

The fact that REST follows HTTP Pull protocols makes the layering possible and practical.  If the system had to notify the client when the coffee order was ready, that would be an up-call: the change of state would happen in the repository level, and then the repository would have to call up to the user-communications level.  But that doesn’t happen.

 

The orderService package structure is reusable, “natural” for web services apps, even web apps

So we see that this layered software organization is not just for this particular app, but can be used for any REST server.  Or any web services server, for that matter, SOAP or REST.  Or a web app using JDBC.

 

Even though JDBC can use a long-term TCP connection, it still does only Pull actions from the client. You might think you could hook up database triggers to JDBC, but in fact you can’t do server-to-client notifications via JDBC.

 

(not covered in class--)

The network technology to do notifications is called a publish-subscribe service, or “pub-sub” for short. It can be done with JMS, Java Messaging Service, another technology of Java EE, with the help of longer-term TCP connections to a database.  It’s not an easy thing to work with.

 

Event Handling the REST way: using feeds

The closest thing in the REST world to notification is an event “feed”, using the Atom protocol (Chap. 7 in Webber et al.), or the older RSS protocol.  A feed doesn’t deliver events, but it organizes them to make it easy for clients to pick them up now and then at their own convenience.

 

The example in Chap. 7: Restbucks has occasional price changes, special drinks to put on the menu, etc. These changes to its basic catalog are “events” that get put in a “feed”.  The individual coffee shops “poll” the feed to pick up these changes and apply them to their local menus.  That’s the REST way to handle events.

 

The APIs between the layers

OK 3 layers. That means 2 APIs between layers:

Call into business layer:  the Service API, tells what the service can do

 

Look at Software Layers handout

 

In pa4, you will extend these APIs to cover payment and receipts and options.

 

We want to go on to Chapter 5 to look at the hypermedia version of orderService, which comes with an Jersey implementation I’ll post as orderDap, after converting it to tomcat.  It is useful for pa4 because it has support for payments and receipts.

 

Q: What’s hypermedia?  The idea that a response from one URI should present the all the next-URIs that follow from that state, to guide the user around the service.  We are not returning URIs, just information relevant to the resource of the URI.  In Chapter 5, the responses contain URIs too.

 

But first, we should look at other “plain” REST services, i.e., not hypermedia.  There’s more we can do with just URI templates and XML messages.

 

 

The Jersey REST Samples.

Jersey comes with a whole distribution of samples, available in a zip file for example at http://download.java.net/maven/2/com/sun/jersey/samples/jersey-samples/1.0.3/

 

One of the samples is a bookmark app that  has users with bookmarks like the example we just looked at, with URI template  /users/{userId}/bookmarks/{bookmarkId}.

 

However it serves JSON and uses JPA, so it’s not directly in our ballpark.

 

Another Jersey sample is a bookstore REST service: items are CDs or books, CDs have tracks.  It shows how we can use inheritance in the representational POJOs.

 

Bookstore 

GET 

/count 

Bookstore 

GET 

/time 

Bookstore 

GET 

/items/{itemid} 

Book, CD 

GET 

/items/{itemid}/tracks/{num} 

Track 

GET 

 

The Bookstore resource returns a list of items, either CDs or books. The resource dynamically references a Book or CD resource using the getItem method that is annotated with @Path. Both the Book and CD resources inherit from the Item class, therefore, the item can be managed as an Item whether it’s really a Book or CD.

 

This shows an example where subresources could more reasonably be used than the simple firstRest2 case, that is, hand off to a subresource to handle the individual track requests.

 

 

Richardson and Ruby’s Bookmark Service: see paper handout on URIs

Their book on the actual delicious site: http://delicious.com/leonardr/restbook

 

Look at R&R’s bookmark service, based on del.icio.us bookmark service.

R&R’s book has lots of good guidance on designing REST APIs.

 

See handed out URI templates to describe the service.  Well, not all of it, but the core part.

 

See users resource, familiar setup, like orders in orderService.

 

See bookmark management running at second level in URIs: a new feature to us.

Template: /users/{userId}/bookmarks/{bookmarkId}.

 

Each user has a set of bookmarks, each id’d by MD5 hashes of the actual bookmark.

(it’s a problem to use the URL itself, see the book, and del.icio.us does it this way.)

Java can compute MD5 hashes using MessageDigest in JDK.

 

POST to collection URI to add one, GET, PUT, DELETE on individual bookmarks.

Also here, as in firstRest2: GET to a collection URI: GET to bookmarks for a user to get all or some of them using query string. This returns the XML representations of the bookmarks, not just a list of URIs back into the service, so this is not a hypermedia service. (You can ask for atom feeds.)

 

Use of query string: a new feature to us, for REST services.

--to specify a date or range of dates on a query

.../?timestamp >= 1280296860145  (Unix time, seconds since Jan 1 1970)

 

--Another query: ?limit=100

Could have ?start=50, but not implemented here.

 

Another idea: use of conditional HTTP GET

From HTTP 1.1 spec, now linked from class web page under HTTP:

 

The semantics of the GET method change to a "conditional GET" if the request message includes an If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match, or If-Range header field. A conditional GET method requests that the entity be transferred only under the circumstances described by the conditional header field(s). The conditional GET method is intended to reduce unnecessary network usage by allowing cached entities to be refreshed without requiring multiple requests or transferring data already held by the client.

 

The If-Modified-Since is a request header, and the corresponding server response usually has the Last-Modified header showing the timestamp related to the response representation.  See Webber et al, pg. 174 for actual header listings, there discussed in terms of caching. If there are no new-enough ones, the client gets back HTTP 304 “Not Modified”.  Of course this means the server needs to timestamp the data used for the representations.  Webber et al, pg. 83 notes that the time used here is good to one second.

 

Looking at the implementation (R&R, pg. 192), we see that this server uses the If-Modified-Since header.  The client can use this header to filter out old bookmarks the client doesn’t want to see.    If there are bookmarks recent enough, they are represented in XML and returned to the user. If not, HTTP 304 is returned.  Note this is implemented in Ruby in this book.

 

Handling query params in JAX-RS: close to HTML form params, since both are request parameter values. Recall @FormParam annotation for service method param to provide incoming form param to Java. Similarly,  could have, for GET /users/{username}/bookmarks?timestamp > 12345678—

 

@GET

@Path(“/{username}/bookmarks)”)

public BookmarkList getBookmarks (@PathParm(“username”) String user, @QueryParam(“timestamp”) long timestamp) …

 

 For the incoming header, use @HeaderParam(“If-Modified-Since”) annotation on a method param.

 

Handling Hierarchical URIs in Jersey:  Using Subresources

 

Hierarchical URIs like /users/{userId}/bookmarks/{bookmarkId}.

 

Jersey implementation of services for these multilevel URI patterns—isn’t it a mess?

 

There’s a concept of subresource that keeps things from blowing up in complexity.

 

Basic Idea: processing the URI from left to right--

/users/{userId}/bookmarks/{bookmarkId}

<-main resource class-> <--subresource class------------->

                       |

                       |handoff from main resource to subresource object

 

 

The Bookmarks Project: Sketch of Jersey Implementation using a Subresource

 

It’s common to handle two related URI segments in one class, so for example for bookmarks

/users/{username}/bookmarks/{id}

<--users resource-><--bookmarks-->

 

UsersResource:

@Path(/users)  on the class

@GET on a method to handle GET  /users             

 

@Path(“{username}”)

@GET on a method to handle GET /users/username

 

@Path(“bookmarks”)

return new Bookmarks subresource object

 

Bookmarks SubResource: no @Path on class

 

@GET on a method to handle GET /users/username/bookmarks

 

@Path(“{bookmarkId}”)

@GET on a method to handle GET /users/username/bookmarks/id

 

Handling two or more PathParams at once: examples from Burke’s RESTful Java with JAX-RS

 

@Path (“/customers”)

public class CustomerResource {

...

@Path(“{first}-{last}”)

@GET

@Produces (“application/xml”)

public Customer getCustomer(@PathParam(“first”) String firstName,

                                                   @PathParam(“last”) String lastName) {

...

}

 

handles GET /customers/bill-burke.  Assumes no –‘s in names.

 

Example returning an image (pg. 66, Burke)

 

@Path(“/cars/{make}”)

public class CarResource {

 

@GET

@Path(“/{model}/{year}”)

@Produces(“image/jpeg”)

public Jpeg getPicture(@PathParam(“make”) String make,

                                @PathParm(“model”) String model,

                                @PathParam(“year”) String year)

{

...

}

 

handles  GET /cars/ford/taurus/2003, sends jpeg for it.

 

Handling queries: more examples from Burke’s RESTful Java with JAX-RS

 

@Path (“/customers”)

public class CustomerResource {

...

@GET

@Produces (“application/xml”)

public Customer getCustomers(@QueryParam(“start”) int start,

                        @QueryParam(“size”) int size) {

...

}

 

Handles GET /customers?start=10&size=20

 

We can specify default values too:

@Path (“/customers”)

public class CustomerResource {

...

@GET

@Produces (“application/xml”)

public Customer getCustomers(@DefaultValue(“0”)  @QueryParam(“start”) int start,

                       @DefaultValue(“10”)  @QueryParam(“size”) int size) {

...

}