Introduction to REST and JAX-RS
-
Upload
ted-pennings -
Category
Technology
-
view
2.362 -
download
1
description
Transcript of Introduction to REST and JAX-RS
Java REST in PracticeAsynchronous JAX-RS
Ted Pennings16 December 2010
REST Overview
REST is an architectural style
Client - Server
Most often over HTTP with JSON or XML
Describes the location of resources + actions
REST PrinciplesResource-based
Stateless
Cacheable
Layered, with optional intermediaries
Safety / Idempotency
The Basic Operations
CRUD (Create, Read, Update, Delete)
Performed atomically on one uniquely identified asset or a set of assets
REST with HTTPREST verbs apply directly to HTTP methods
GET - READ
POST - CREATE
PUT - UPDATE
DELETE
Encoded in JSON or XML
Bonus!OPTIONS
HEAD
TRACE
Widget Registry at http://server/widgets
Create a Widget (Bolt, weighs 10g)
REST HTTP Example
POST /widgetsHost: serverUser-agent: Ted’s PresentationContent-type: Application/JSONContent-length: 115
{ widget : { type : ‘bolt’, weight : { amount : 10, unit : ‘grams’ } }}
HTTP/1.1 200 OKDate: Wed, 15 Dec 2010 23:59:59 GMTContent-Type: text/plainTransfer-Encoding: chunked
{ newAssetId: 15 }
Alternatively, could redirect to new asset with Location header
Widget Registry at http://server/widgets
Get Widget from last slide (ID 15 )
Another HTTP Example
GET /widgets/15Host: serverUser-agent: Ted’s Presentation
HTTP/1.1 200 OKDate: Wed, 15 Dec 2010 23:59:59 GMTContent-Type: text/plainTransfer-Encoding: chunkedContent-length: 135
{ widget : { id : 15, type : ‘bolt’, weight : { amount : 10, unit : ‘grams’ } }}
Also available in browser at http://server/widgets/15
Widget Registry at http://server/widgets
Update Widget previously created
Final HTTP Example
HTTP/1.1 200 OKDate: Wed, 15 Dec 2010 23:59:59 GMTContent-Type: text/plainTransfer-Encoding: chunked
PUT /widgets/15Host: serverUser-agent: Ted’s PresentationContent-type: Application/JSONContent-length: 134
{ widget : { id : 15, type : ‘bolt’, weight : { amount : 10, unit : ‘grams’ } }}
(weight was actually 1 gram, typo)
What We Just Saw
REST is resource-oriented
Assets are identified with URLs
The HTTP method specifies the operation
So What?
Putting the important information (what, how) at the HTTP protocol-level allows intermediaries to act and advise
Increased scalability and lower costs
Intermediaries
Two categories:
- Proxies (client-chosen)
- Gateways (provider-chosen)
Client Intermediaries
Mostly proxies
May or may not cache
May alter Javascript for client safety
Firewalls (eg block NSFW + illegal content)
Provider IntermediariesCaching reverse-proxies and CDNs
Message remediation / translation
Security (eg XSRF nonces)
Also, protocol-level load balancing / failover
Should be invisible to client
Safety
Data retrieval methods are considered safe
Should not alter application data
GET / HEAD / OPTIONS / TRACE
Highly Cacheable by intermediaries!
IdempotencyMethods that may be executed more than once with the same result are idempotent
PUT / DELETE
All safe methods are idempotent
POST is not always idempotent
Enter JAX-RS
Abstract specification for tagging resource endpoints and operations in Java code
Annotation-driven
Exposes results of method calls in the same way JAX-WS or Spring-WS does
Using JAX-RSProviders implement it (like JPA)
Provider agnostic ; can easily switch (unlike JPA)
Jersey is the reference implementation
Can couple with message marshallers/unmarshallers
Most rely on JAXB, even for JSON
JAX-RS AnnotationsThe litany found in the javax.ws.rs package...
@Path(“/path”)
@GET / @POST / @PUT / @DELETE /etc
@Produces + @Consumes(“text/plain”)
@PathParam + @HeaderParam + @QueryParam
Creating a Time Service
@Path("/time")public class TimeJaxRsResource {
@GET @Produces("text/plain") public String getCurrentTime() { return new Date().toString(); }
}
http://yourserver/context/time
Using Paths
@Path("/time")public class TimeJaxRsResource { @GET @Path("/eastern") @Produces("text/plain") public String getCurrentEasternTime() { DateFormat format = new SimpleDateFormat(); TimeZone eastern = TimeZone.getTimeZone( "America/New_York"); format.setTimeZone(eastern); return format.format(new Date()); }
}
http://yourserver/context/time/eastern
Using Path Variables
@Path("/time")public class TimeJaxRsResource { @GET @Path("/tz/{timezone}") @Produces("text/plain") public String getTime(@PathParam ("timezone") String tz) { DateFormat format = new SimpleDateFormat(); TimeZone timezone = TimeZone.getTimeZone(tz); format.setTimeZone(timezone); return format.format(new Date()); }
}
http://yourserver/context/time/tz/America_Chicago
What We’ve CreatedStateless
Unfortunately, not useful if cached
Not necessarily asynchronous from a client perspective (due to accuracy concerns)
Message MarshallingJSON to marshall/unmarshall messages
Most commonly used: Jackson
Create a file containing in the following org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider
META-INF/services/javax.ws.rs.ext.MessageBodyReader
META-INF/services/javax.ws.rs.ext.MessageBodyWriter
Example : Prime Numbers
Prime number generation is computationally expensive but fairly simple
Worker thread(s) generate prime numbers
A web UI shows the latest additions http://primes.tedpennings.com/
The Prime Algorithm long x, y; for (x = start; x < Long.MAX_VALUE; x++) { if (x % 2 != 0 || x == 2) { for (y = 2; y <= x / 2; y++) { if (x % y == 0) { break; } } if (y > x / 2) { System.out.println("Discovered prime: " + x); repo.add(x); } } }
The Workers
Stateless loop of code trying to identify primes
Add to MongoDB once found
Simple JAR distributed to workers
Currently, only one; possibility for more
The App
Methods to find the most recent number and batches of numbers greater than X
Exposed over RESTful HTTP with JSON
Runs in Jetty, fronted by an intermediary
http://primes.tedpennings.com/primes/since/13183229
Example Code - Service
@Path("/")public class PrimeJaxRsResource {
private final MongoPrimeRepository repo = new MongoPrimeRepository(); @GET @Path("/since/{since}") @Produces("application/json") public Set<Long> getPrimesSince(@PathParam("since") long since) { LOG.info("Showing the default number of primes since " + since); return repo.getPrimes(since); }
}
http://prime.tedpennings.com/primes/since/1500
The Intermediary
Nginx reverse-proxying Jetty (same node)
Caches all GET operations
The Web UI
Periodical Ajax requests for the numbers since the most recent request (asynchronously)
Does not require full batches
Size varies based on complexity + worker speed
All JavaScript, with jQuery
Demo and Code
Demo and Code Walkthrough
http://primes.tedpennings.com
http://s3.tedpennings.com/prime-jaxrs.zip
Possible Follow-up
Use some kind of MapReduce to distribute workload across multiple workers (Hadoop?)
Use Chef or Puppet to dynamically provision workers and initialize application
Resources (haha)Roy Fielding’s Thesis http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
Jersey site http://jersey.java.net
Wikipedia (surprisingly good for this)
This awesome font : http://www.dafont.com/hand-of-sean.font