thinking restfully
DESCRIPTION
Presentation at the Greek Java Hellenic group about the architectural principles of RESTTRANSCRIPT
JHUG 17 Dec 2011
REST Thinking RESTfully Stelios Gkorilas
JHUG 17 Dec 2011
Contents 1. Types of services 2. What is REST? 3. Web services and the REST way 4. Example: S3 5. Security 6. Jersey/JAX-RS 7. CTR
JHUG 17 Dec 2011
Distributed services • The everlasting need to (re-)use logic as black box
• Even across different machines and platforms • Gave birth to distributed objects and several protocols for
remoting (e.g. CORBA, DCOM, RMI) • Web services prevailed because the web is ubiquitous and
scalable • Web services provide the means to integrate disparate systems
and expose reusable business functions over HTTP • Mostly SOAP services up to now in RPC style
• Some serve HTML, JSON, plain text, or binary documents, but most use XML
• WSDL and the WS-* specs • HTTP is used as the transport service not the application protocol
JHUG 17 Dec 2011
Service styles • RPC services • Message oriented services • Resource oriented services
JHUG 17 Dec 2011
RPC style • The request message identifies the procedure to be
executed, and the fixed set of parameters that map directly to the parameters of the remote procedure
• XML-RPC and later the WS-* stack
• Procedure arguments are tightly coupled messages • Usually flat APIs • Communication through proxies that have to be
regenerated in case of change • e.g. JAX-WS
JHUG 17 Dec 2011
Message oriented • Services that have Message APIs (a.k.a. Document APIs)
receive one or more self-descriptive message types at a given URI
• They are not coupled to procedure names hence they can easier change
• They can constitute commands, events or just documents • They contain values that identify their type and/or
handling
JHUG 17 Dec 2011
making a Google search the SOAP way POST search/beta2 HTTP/1.1 Host: api.google.com Content-Type: application/soap+xml SOAPAction: urn:GoogleSearchAction <?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body> <gs:doGoogleSearch xmlns:gs="urn:GoogleSearch"> <key>00000000000000000000000000000000</key> <q>jhug user group</q> <start>0</start> <maxResults>10</maxResults> <filter>true</filter> <restrict /> <safeSearch>false</safeSearch> <lr /> <ie>latin1</ie> <oe>latin1</oe> </gs:doGoogleSearch></soap:Body>
</soap:Envelope>
JHUG 17 Dec 2011
Resource oriented • It’s like object oriented – Resources are objects • Resource is the design of data; what we perceive data to
be; it is what we think others might find interesting about our data
• Everything can be a resource • Resources are accessed through a Uniform Interface • Resources are interconnected • Resources have multiple representations • Communication is stateless
JHUG 17 Dec 2011
Resources • Everything can be a resource (like everything can be an object) • A procedure, instances of domain data, files • Examples:
• A list of search results about ‘Mullus barbatus’ • An article • The jhug meeting on Dec 17 • The latest jhug meeting • The software version release 1.1.2.3 • The latest release • The list of unresolved issues of type ‘bug’ and component ‘Launcher’
• Every resource should have a unique identifier, a URI • http://www.jhug.gr/meetings/meet-up/17-dec-2011
JHUG 17 Dec 2011
What is REST? • Architectural style • Architectural constraints • A way to evaluate architectures • Design principles • Key properties of a simple (not simplistic) application • The null style: Start with system needs as a whole,
without constraints, and then incrementally identifies and applies constraints to elements of the system in order to differentiate the design space
• Representational State Transfer • You request a resource and a representation of its state is
returned
JHUG 17 Dec 2011
HTTP Example Request GET /meetups/latest HTTP/1.1 Host: www.jhug.gr Accept: application/xml
Response HTTP/1.1. 200 OK Date: Sat, 17 Dec 2011 13:45:34 GMT Server: Apache/1.3.6 Content-Type: application/xml; charset=UTF-8 <?xml version="1.0" encoding="UTF-8"?> <meetup xmlns="...">
<occurred date=".."/> <presentations> ... </presentations> <next uri=".."/>
</meetup>
JHUG 17 Dec 2011
HTTP, URIs & XML define the web • Operations: GET, PUT, DELETE, POST
• And the less known HEAD, OPTIONS • Headers
• content-type • Accept-Language
• Media types • text/plain • text/xml • application/atom+xml
• Response codes • 2xx Success • 3xx Redirect • 4xx Client Error • 5xx Server Error
• URIs and URLs define the web
• XML: content attributes and structure
An Application protocol for service logic
JHUG 17 Dec 2011
REST constraints (Fielding dissertation) • Client/server • Uniform Interface • Layered System • Stateless • Cache • Code on Demand
JHUG 17 Dec 2011
Resources and the uniform interface • HTTP standard methods: GET, PUT, POST, DELETE • HEAD and GET should not modify anything • Idempotent: PUT DELETE GET HEAD
• HTTP is the application protocol defining service behaviors
• GET /meetups/latest instead of getLatestMeetup() • RPC verbs become REST nouns
• GET the more recent state of the resource • PUT/POST a representation that alters the state of the
resource
JHUG 17 Dec 2011
Representations • Representations have media types • Multiple formats for different needs
• Content negotiation • Accept: application/json (request) • Content-Type: application/json (response)
• URI • /meetups/latest.json
JHUG 17 Dec 2011
Addressability • Representations should be addressable • Increase the surface of the service
• Client can enter the application where convenient
• A URI can never point to more than one resource
JHUG 17 Dec 2011
Interconnected Resources • Resources are not just data but hypermedia • Hypermedia as the engine of state • Representations contain links to other resources • A representation may contain links ot other states of the resource • Paths a client can follow • Makes clients more resilient to changes <?xml version="1.0" encoding="UTF-8"?> <meetup xmlns="...">
<occurred date="17-12-2011"/> <presentations> <presentation ref="/presentations/title/disruptor"/> <presentation ref="/presentations/title/rest"/> <presentation ref="/presentations/title/sw-dev-practices"/> </presentations> <next ref="/meetings/date/17-01-2011"/>
</meetup>
JHUG 17 Dec 2011
Stateless • HTTP is stateless • All information needed for processing part of the request • No session on the server
• No session ids exchanged (jsessionId, phpSessionId, etc. )
• Application state belongs to the client • Resource state alone belongs to the server
• Simplifies server and client logic, allows scalability e.g. http://www.google.gr/search?q=jhug&start=20
JHUG 17 Dec 2011
Cacheability • Conditional queries
• Cacheable when last-modified and etag are used (response headers)
• If- Modified-Since and If-None-Match (request headers) • 304 Response Code when not modified with no entity body
• Cache proxies and other commodity caching technologies
JHUG 17 Dec 2011
REST Patterns • Paths for hierarchy
• jhug/discussions/april
• Post for not owned URIs • Container items • Jhug/discussions/1342
• PUT for URIs defined by the client • Jhug/presentations/rest
• Semicolon (;) or comma (,) for name/value or matrix values • jhug/presentations/author,gkorilas/rest
• Query string for algorithmic resources • Jhug/search?q=“rest”
JHUG 17 Dec 2011
Think Resource Oriented • Define the data set • Expose data as resources • Assign URIs to resources • Decide the UI commands accepted • Decide the representations accepted • Decide the representations served • Add hypermedia links between them
JHUG 17 Dec 2011
REST + • Serve representations suitable for many clients
• The uniform interface allows all http clients to easily consume a suitable representation
• Content negotiation can allow a single URL to serve content to a browser, a JS client that is interested in JSON or a mobile phone client interested in an XML representation
• Cacheable by commodity technologies • Scalable • Fail over • Clients:
• Browser friendly • Easy support by many languages • Bookmarkable • Data formats
• It is the natural way of the web!
JHUG 17 Dec 2011
REST Security standards
JHUG 17 Dec 2011
The Amazon S3 Service • S3 “buckets” and S3 “objects”
• Bucket can only contain objects • Bucket names are unique in S3 • Object has a name (key) and content (value) • Object has a reference to the parent bucket • Object has metadata key-value pairs; can also be http headers like
content-type or content-disposition
• Three types of resources • List of your buckets (https://s3.amazonaws.com/) • A particular bucket (https://s3.amazonaws.com/{name-of-bucket}/). There
can be up to 100 resources of this type. • A particular S3 object inside a bucket (https://s3.amazonaws.com/
{name-of- bucket}/{name-of-object}
JHUG 17 Dec 2011
S3 resources and methods GET HEAD PUT DELETE
(/) List your buckets
- - -
/{bucket} List objects of bucket
- Create the bucket
Delete the bucket
/{bucket}/{object}
Object’s value and metadata
Object’s metadata
Set the object’s value and metadata
Delete the object
JHUG 17 Dec 2011
S3 Security • Message digest of the canonical string of the request with a
secret key (amazon knows it too) • {http method}{content-type}{date}{amazon headers}{path}
• Add it to http Authorization: header
• Add it to query string together with expires date to make bookmarkable (https://s3.amazonaws.com/stelinio/rest.pdf# ?Signature=J%2Qu6krT3j0zaaFXjsLbowdfzExQ%3D # &Expires=1162156788&AWSAccessKeyId=0F9RBCLB5274NKTJ4DA3")
• Access policies • Private, public-read, public-write, authenticated read
JHUG 17 Dec 2011
HTTP security, OAuth • http basic • http digest • http client certificate
• OAuth • Delegated user authentication solution - Valet key principle • Client, server, resource owner (OAuth love triangle) • client credentials, temporary credentials, and token credentials
JHUG 17 Dec 2011
Java REST Services • Java EE 6 specification: JAX-RS • Jersey: Reference implementation of JSR 311 • Available as standalone and enterprise
JHUG 17 Dec 2011
Standalone example setup <servlet>
<servlet-name>jersey</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>eu.ema.eudract.rest</param-value> </init-param> <load-on-startup>1</load-on-startup>
</servlet> <dependency>
<groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId>
</dependency> <dependency>
<groupId>com.sun.jersey</groupId> <artifactId>jersey-json</artifactId>
</dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-atom</artifactId> </dependency>
JHUG 17 Dec 2011
JAX-RS Resources Annotate POJOs @Path("/meetups")@Singleton()public class MeetUpsResource {
@GET()@Path("/latest")@Produces("text/plain")public String getLatestMeetUp() { return getDataService().getLatestMeetUp().toString();}
@GET()@Path("/next")@Produces("text/plain")public String getNextMeetUp() { return getDataService().getNextMeetUp().toString();}@GET()@Produces(MediaType.APPLICATION_JSON)public MeetUps getAllMeetUps() { return getDataService().getAllMeetUps();}
}
JHUG 17 Dec 2011
Methods & Paths • @javax.ws.rs.GET • @javax.ws.rs.PUT • @javax.ws.rs.POST • @javax.ws.rs.DELETE • @javax.ws.rs.HEAD
• Paths: Most specific match wins
JHUG 17 Dec 2011
JAX-RS Injection • @javax.ws.rs.PathParam
• values from URI template parameters • @javax.ws.rs.MatrixParam
• URI’s matrix parameters. • @javax.ws.rs.QueryParam
• Query String parameters • @javax.ws.rs.FormParam
• form-encoded key-value pairs • @javax.ws.rs.HeaderParam
• HTTP request headers • @javax.ws.rs.CookieParam
• HTTP cookies set by the client • @javax.ws.rs.core.Context
• All-purpose injection annotation. It allows you to inject various helper and informational objects that are provided by the JAX-RS API e.g.
• @Context final HttpServletRequest request• @Context final SecurityContext secCtx
JHUG 17 Dec 2011
JAX-RS Content Handling • MIME types • Automatic content negotiation • Automatic content serialization
• Jaxb representation → XML, JSON • Byte[] → Binary or */* • String → text/* • MultiValuedMap<String, String> → application/x-www-form-
urlencoded
• StreamingOutput • @Providers
JHUG 17 Dec 2011
JAX-RS Error Handling • HTTP Error Codes • WebApplicationException • ExceptionMapper
throw new WebApplicationException(new RuntimeException (“Timeframe not an Integer"),
Response.Status.NOT_ACCEPTABLE);@Provider public class EntityNotFoundMapper implements ExceptionMapper<EntityNotFoundException>{ public Response toResponse(EntityNotFoundException e){
return Response.status(Response.Status.NOT_FOUND).build(); }
}
JHUG 17 Dec 2011
Enforcing security • @RolesAllowed({“admin”,”client-admin”}) • @PermitAll
• Any authenticated user • @SecurityContext
public interface SecurityContext{ public static final String BASIC_AUTH = "BASIC"; public static final String CLIENT_CERT_AUTH = "CLIENT_CERT"; public static final String DIGEST_AUTH = "DIGEST"; public static final String FORM_AUTH = "FORM"; public Principal getUserPrincipal(); public boolean isUserInRole(String role); public boolean isSecure(); public String getAuthenticationScheme();}
JHUG 17 Dec 2011
Example @Path(”/presentations")@Singleton()public class PresentationsResource {
@PUT()@Path(”/presentation/{name}”)@RolesAllowed(”admin”)public void addPresentation(@PathParam name, InputStream is){ return getDataService().addPresentation(is);}
@GET()@Path(”/presentation/{name}")public StreamingOutput getPresentation(@PathParam name) { return new StreamingOutput() { @Override public void write(OutputStream output) throws IOException {
stream( getDataService().getPresentation(name) , output ); } }
}
}
JHUG 17 Dec 2011
CTR • Clinical Trials Register
• (https://www.clinicaltrialsregister.eu/)
• Rest services • Data to other agency html pages • Content to the World Health Organization • Data to the web application users
• Rest clients • JS code as the client • Controller servlet • JSP <c:import url=“/trial/2010-022009-16/GB”/> • A guy at World Health Organization every Tuesday at 19:00
JHUG 17 Dec 2011
Data consumed by html pages (1/3) @Path("/trials")@Singleton()public class TrialsMetaDataResource {
@GET()@Path("/count/public")@Produces("text/plain")public String countPublicTrials() { return getDataService().countPublicClinicalTrials().toString();}
@GET()@Path("/count/public/under18")@Produces("text/plain")public String countUnder18PublicTrials() { return getDataService().countPublicClinicalTrialsWithSubjectsUnder18().toString();}@GET()@Path("/landing")@Produces(MediaType.APPLICATION_JSON)public LandingPageMetadata landingPageMetadata() { Integer total = getDataService().countPublicClinicalTrials(); Integer under18 = getDataService().countPublicClinicalTrialsWithSubjectsUnder18(); LandingPageMetadata metadata = new LandingPageMetadata(total, under18); return metadata;}
…}
JHUG 17 Dec 2011
Data consumed by html pages (2/3) @XmlRootElement()@XmlAccessorType(value = XmlAccessType.PROPERTY)public class LandingPageMetadata implements Serializable {
private static final long serialVersionUID = -8784258618018188874L;
private Integer numberOfPublicClinicalTrials;private Integer numberOfPublicClinicalTrialsWithSubjectsUnder18;
public LandingPageMetadata() {…}
public LandingPageMetadata(Integer numberOfPublicClinicalTrials, Integer numberOfPublicClinicalTrialsWithSubjectsUnder18) {…}@XmlElement(name="total")public Integer getNumberOfPublicClinicalTrials() {…}public void setNumberOfPublicClinicalTrials(Integer numberOfPublicClinicalTrials) {…}
@XmlElement(name="under18")public Integer getNumberOfPublicClinicalTrialsWithSubjectsUnder18() {…}
public void setNumberOfPublicClinicalTrialsWithSubjectsUnder18(Integer
numberOfPublicClinicalTrialsWithSubjectsUnder18) {…}
@Overridepublic String toString() {…}
}
JHUG 17 Dec 2011
Data consumed by html pages (3/3) function showNumbers() {
$.getJSON('api/trials/landing', function(data) { var total = data['total']; var under18 = data['under18']; $("#total").text(total); $("#under18").text(under18);});
}
JHUG 17 Dec 2011
Streaming Content (1/2) @Path("/download")public class DownloadResource {
@GET@Path("/summary")public Response downloadSummaryTrials(@Context final HttpServletRequest request, @QueryParam ("mode") final String mode) {return Response.ok(new SummaryStreamingOutput(request, mode),MediaType.APPLICATION_OCTET_STREAM) .header("content-disposition","attachment; filename = trials-summary.txt").build();}@GET@Path("/full")public Response downloadFullTrials(@Context final HttpServletRequest request, @QueryParam ("mode") final String mode) {return Response.ok(new FullStreamingOutput(request, mode),MediaType.APPLICATION_OCTET_STREAM) .header("content-disposition","attachment; filename = trials-full.txt").build();}@GET@Path("/trial/{eudractnumber}/{nca}")public Response downloadFullCta(@Context final HttpServletRequest req, @PathParam ("eudractnumber") String eudractnumber, @PathParam("nca") String nca) {return Response.ok(new CtaStreamingOutput(req, eudractnumber, nca),MediaType.APPLICATION_OCTET_STREAM) .header("content-disposition","attachment; filename = trial.txt").build();}
}
JHUG 17 Dec 2011
Streaming Content (2/2) public class CtaStreamingOutput implements StreamingOutput{
public CtaStreamingOutput(HttpServletRequest request, String euNumber, String nca) {…}
public void write(OutputStream output) throws IOException { TextSerializer ser = new TextSerializer(); ser.setOutputStream(output); CtaIdentification pubCta = mapper.map (eudractNumber, nca); ser.serializeCtaFull(pubCta);}
}
JHUG 17 Dec 2011
RSS 2.0 instead of built in Atom (1/2) @GET@Path("/bydates”)@Produces("application/rss+xml")public SyndFeed getFeed(@Context final HttpServletRequest request) {
String feedType = "rss_2.0”;SyndFeed feed = new SyndFeedImpl();feed.setFeedType(feedType);String url = request.getRequestURL().toString().replaceFirst("/rest/ feed/bydates", ”/search") + "?" + request.getQueryString();feed.setLink(url);feed.setTitle("EU Clinical Trials Register RSS Feed");feed.setDescription("This provides a regular feed of new or updated clinical trial information published on the EU Clinical Trial Register and matching the search subscribed to.");List<CtrDocument> docs = search(request); for(CtrDocument doc: docs){ SyndEntry entry = buildEntry(doc, entryBasicUrl, countryUrl); feed.getEntries().add(entry);}LOG.info("Generated RSS feed {}", feed.getLink());return feed;
}
JHUG 17 Dec 2011
RSS 2.0 instead of built in Atom (2/2) @Provider@Produces("application/rss+xml")@Consumes("application/rss+xml")public class RomeRssSupport implements MessageBodyWriter<Object>{
public boolean isWriteable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {return (SyndFeed.class.isAssignableFrom(type));
}
public long getSize(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {return -1;
}
public void writeTo(Object feedOrEntry, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream outputStream) throws IOException {if (feedOrEntry instanceof SyndFeed) { SyndFeed feed = (SyndFeed)feedOrEntry; SyndFeedOutput output = new SyndFeedOutput(); doc = output.outputW3CDom(feed); Source source = new DOMSource(doc); Result result = new StreamResult(outputStream); TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(); transformer.transform(source, result); }
}}
JHUG 17 Dec 2011
Resources
ptg6899256
• Restful Web Services - Leonard Richardson and Sam Ruby
• Service Design Patterns - Robert Daigneau • Restful Java - Bill Burke • www.amazon.com • http://icondrawer.com • http://www.iconeden.com • http://www.iconshock.com