45
JHUG 17 Dec 2011 REST Thinking RESTfully Stelios Gkorilas

Thinking restfully

Embed Size (px)

DESCRIPTION

Presentation at the Greek Java Hellenic group about the architectural principles of REST

Citation preview

Page 1: Thinking restfully

JHUG 17 Dec 2011

REST Thinking RESTfully Stelios Gkorilas

Page 2: Thinking restfully

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

Page 3: Thinking restfully

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

Page 4: Thinking restfully

JHUG 17 Dec 2011

Service styles • RPC services • Message oriented services • Resource oriented services

Page 5: Thinking restfully

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

Page 6: Thinking restfully

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

Page 7: Thinking restfully

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>

Page 8: Thinking restfully

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

Page 9: Thinking restfully

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

Page 10: Thinking restfully

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

Page 11: Thinking restfully

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>

Page 12: Thinking restfully

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

Page 13: Thinking restfully

JHUG 17 Dec 2011

REST constraints (Fielding dissertation) • Client/server • Uniform Interface •  Layered System • Stateless • Cache • Code on Demand

Page 14: Thinking restfully

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

Page 15: Thinking restfully

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

Page 16: Thinking restfully

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

Page 17: Thinking restfully

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>

Page 18: Thinking restfully

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

Page 19: Thinking restfully

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

Page 20: Thinking restfully

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”

Page 21: Thinking restfully

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

Page 22: Thinking restfully

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!

Page 23: Thinking restfully

JHUG 17 Dec 2011

REST Security standards

Page 24: Thinking restfully

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}

Page 25: Thinking restfully

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

Page 26: Thinking restfully

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

Page 27: Thinking restfully

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

Page 28: Thinking restfully

JHUG 17 Dec 2011

Java REST Services •  Java EE 6 specification: JAX-RS •  Jersey: Reference implementation of JSR 311 • Available as standalone and enterprise

Page 29: Thinking restfully

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>

Page 30: Thinking restfully

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();}

}

Page 31: Thinking restfully

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

Page 32: Thinking restfully

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

Page 33: Thinking restfully

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

Page 34: Thinking restfully

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(); }

}

Page 35: Thinking restfully

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();}

Page 36: Thinking restfully

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 ); } }

}

}

Page 37: Thinking restfully

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

Page 38: Thinking restfully

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;}

…}

Page 39: Thinking restfully

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() {…}

}

Page 40: Thinking restfully

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);});

}

Page 41: Thinking restfully

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();}

}

Page 42: Thinking restfully

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);}

}

Page 43: Thinking restfully

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;

}

Page 44: Thinking restfully

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); }

}}

Page 45: Thinking restfully

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