Introduction to REST and JAX-RS

Preview:

DESCRIPTION

An introduction to the architectural style REST and an overview of implementing an application in JAX-RS, the JSR-311 Java REST API.

Citation preview

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

Contact

http://ted.pennin.gs / ted@pennin.gs

twitter: @thesleepyvegan

Recommended