Soyons 

RESTful 

avec 

RESTX !

by @xavierhanin


http://slid.es/xavierhanin/restx




/me

Xavier Hanin




Lead Architect / Developer
Bordeaux Agency Manager
@ 4SH

Community

Creator of BordeauxJUG (2008)

Frequent speaker (Devoxx BE, Devoxx FR, ApacheCon, JavaZone, BordeauxJUG, ...)

Teacher @ Institut Polytechnique de Bordeaux (since 2004)

Winner of CodeStory S02


Open Source

Creator of Apache Ivy (2004)
Creator of Voxxr.in (2012)

Many side projects / contributions
wicket-contrib-push, xooki, xooctory, twitter4j, ...

Creator of RESTX (2013)

Web Development


Servlet, JSP, Velocity, Freemarker, JSTL, JSF, RichFaces, ADF Faces, Wicket, GWT, Struts, Spring MVC, Restlet, Play! Framework, SimpleFramework, PHP, HTML5, CSS3, JS, NodeJS, Dojo, ExtJS, jQuery, AngularJS

Motivation


Agenda


  1. REST
  2. RESTX

REST


Representational State Transfer


Architecture Style


Web


Roy Fielding Thesis (2000)

Elements



Resources

Resources Identifiers

Representations

Constraints


Client Server
Stateless
Cacheable
Uniform Interface
Layered System
Code On Demand (optional)

Resource


Any information that can be named can be a resource - Roy Fielding

A person
The list of persons living in Bordeaux
Today's weather in La Rochelle

Resource Identifier

URI = Uniform Resource Identifier
^
|
URL = Uniform Resource Locator

eg
http://restx.io/modules
http://en.wikipedia.org/wiki/Main_Page

Representation


REST components perform actions on a resource by using a representation to capture the current or intended state of that resource and transferring that representation between components - Roy Fielding

Representation

JSON
{
    "name":"Acme Inc",
    "address": {
        "body":"111, av du truc",
        "zipCode":"33700",
        "city":"Merignac"
    },
    "_id":"51eba5766bc8e48ffeaacc89"
}
XML
<company name="Acme Inc" _id="51eba5766bc8e48ffeaacc89">
        <address>
            <body>111, av du truc</body>
            <zipcode>33700</zipcode>
            <city>Merignac</city>
        </address>
    </company>

Uniform interface

HTTP Methods

GET
HEAD
OPTIONS
PUT
POST
DELETE
TRACE
CONNECT

GET

get a resource state representation
nullipotent

GET /companies/51ebab006bc8e48ffeaacc93
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Content-Type:application/json; charset=UTF-8

{    "name":"ACME Inc",
    "address":{
        "body":"1122, pooder st",        "zipCode":"12345 CA",        "city":"Palo Alto"},
    "_id":"51ebab006bc8e48ffeaacc93"
}
    

HEAD

get a resource metadata
nullipotent

eg
HEAD /companies/51ebab006bc8e48ffeaacc93
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Content-Type:application/json; charset=UTF-8

OPTIONS

request for information about the communication options available
nullipotent

eg
Used for CORS (Cross Origin Resource Sharing)
OPTIONS /companies/51ebab006bc8e48ffeaacc93
Origin: http://foo.example
Access-Control-Request-Method: PUT
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS

PUT

put a resource state representation
idempotent
PUT /companies/51ebab006bc8e48ffeaacc93
        
{   "name":"ACME Inc",
    "address":{
        "body":"1122, pooder st",
        "zipCode":"12345 CA",
        "city":"Palo Alto"},
    "_id":"51ebab006bc8e48ffeaacc93"}        
    
HTTP/1.1 200 OK

{   "name":"ACME Inc",
    "address":{
        "body":"1122, pooder st",
        "zipCode":"12345 CA",
        "city":"Palo Alto"},
    "_id":"51ebab006bc8e48ffeaacc93"} 
    

DELETE

deletes a resource
idempotent

eg
DELETE /companies/51ebab006bc8e48ffeaacc93
HTTP/1.1 204 No Content

POST

posts a new resource state representation
"request that the origin server accept the entity enclosed in the request as a new subordinate of the resource"
POST /companies
        
{   "name":"ACME Inc",
    "address":{
        "body":"1122, pooder st",
        "zipCode":"12345 CA",
        "city":"Palo Alto"} }        
    
HTTP/1.1 201 Created

{   "name":"ACME Inc",
    "address":{
        "body":"1122, pooder st",
        "zipCode":"12345 CA",
        "city":"Palo Alto"},
    "_id":"51ebab006bc8e48ffeaacc93"} 
    

Uniform Interface

HTTP status codes
200 OK 
201 Created 
202 Accepted 
204 No Content 
301 Moved Permanently 
303 See Other 
304 Not Modified
...
400 Bad Request 
401 Unauthorized 
403 Forbidden 
404 Not Found
500 Internal Server Error
...

Stateless


such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. - Roy Fielding

RESTX


RESTX


Java lightweight REST framework


Open Source

http://github.com/restx/restx

Apache License

RESTX History

pre history : 2011 framework jewas

4SH only
very low level
Netty based / included HTTP connector
no annotation

RESTX HISTORY

january 2013

starting a new project @ 4SH

AngularJS / REST / MongoDB

focus on server startup time

spring mvc + jetty too slow (2s)

RESTX History


May 2013
First open source version (0.2.5)
restx.io web site 
0.2.6

June ~ July 2013 -> 0.2.7, 0.2.8

September 2013 -> 0.2.9 - first conferences
November 2013 -> 0.30
January 2014 -> 0.31

Getting Started

$ curl -s http://restx.io/install.sh | sh
$ restx
==========================================================
== WELCOME TO RESTX SHELL - 0.31 - type `help` for help
==========================================================

restx> app new
Welcome to RESTX APP bootstrap!
This command will ask you a few questions to generate your app.
For any question you can get help by answering '??'

App name? MyApp        
[...]
Congratulations! - Your app is now ready in `~/projects/myapp`
    

As a Library

Apache Maven:
<dependency>
    <groupId>io.restx</groupId>
    <artifactId>restx-core</artifactId>
    <version>0.31<version>
</dependency>
Apache Ivy:
<dependency org="io.restx" name="restx-core" rev="0.31" />
+ a few additional steps: 
http://restx.io/docs/manual-app-bootstrap.html

First Resource


@Component @RestxResource
public class HelloResource {
    @PermitAll @GET("/message")
    public MyMessage sayHello(String who) {
        return new MyMessage().setMessage(String.format(
                "hello %s, it's %s",
                who, DateTime.now().toString("HH:mm:ss")));
    }
}


$ curl "http://localhost:8080/api/message?who=restx"
{"message":"hello restx, it's 15:53:23"}

Fast Startup


No classpath scanning
Track startup time

Empty app starts in ~ 500ms

App with ~100 routes  ~60 entity classes 
+ mongoDB connection
 starts in ~1.2s

Benefits


Better development cycles

Cloud ready: better warmup requests time

Better for integration tests

no reflection / proxies



Use code generation instead

Based on Annotation Processing
built in Javac

BENEFITS - Knows your code


Parameters names, Parameterized types, ...

@GET("/cities")
public Iterable<City> findCities(Optional<String> name) {
    if (name.isPresent()) {
        return cities.get().find("{name: #}",
            name.get()).as(City.class);
    } else {
        return cities.get().find().as(City.class);
    }
}

@GET("/cities/{oid}")
public Optional<City> findCityById(String oid) {
    return Optional.fromNullable(cities.get().findOne(new ObjectId(oid)).as(City.class));
}

@PUT("/cities/{oid}")
public City updateCity(String oid, City city) {
    checkEquals("oid", oid, "city.key", city.getKey());
    cities.get().save(city);
    return city;
}    

Benefits - See the code


new StdEntityRoute("default#HelloResource#sayHello",
    mapper, new StdRouteMatcher("GET", "/message")) {
       @Override
       protected Optional doRoute(
            RestxRequest request,
            RestxRouteMatch match) throws IOException {
                securityManager.check(request, open());
                return Optional.of(resource.sayHello(
  /* [QUERY] who */ checkPresent(request.getQueryParam("who"),
                        "query param who is required")
                ));
       }
}

Benefits - Impact Analysis








Benefits - Easy Debug



Benefits - More efficient


Pay the price at build time, not runtime

Less CPU cycles
=>

Faster

Cheaper, especially for the cloud "pay for what you use"

Lightweight



NO BRAINER FEATURES

Bundled with best libraries

Google Guava
Rely on Optional<> to mark parameters as optional

Joda Time
Until its standardised in JSR 310

No brainer features

JSON Mapping


Done with Jackson
"High-performance JSON processor"

Very flexible
High performance
Supports BSON
Configured to support JodaTime & Guava

NO BRAINER FEATURES

Validation


Done with Hibernate Validator
All incoming objects are validated

    @Size(min = 4)
    private String name;


NO BRAINER FEATURES

Dependency Injection

With (almost) no classpath scanning
Type safe (based on code generation)
Used to discover plugins

@Component
public class MyComponent {
    public MyComponent(MyDependency dependency) {
       ...
    }
}

NO BRAINER FEATURES

Security

Stateless security
Secured by default

@Component @RestxResource
public class HelloResource {
    @PermitAll @GET("/message")
    public MyMessage sayHello(String who) {
        return new MyMessage().setMessage(String.format(
                "hello %s, it's %s",
                who, DateTime.now().toString("HH:mm:ss")));
    }
}

NO BRAINER FEATURES

Security (2)



@Component @RestxResource
public class HelloResource {
    @RolesAllowed("admin") @GET("/message")
    public MyMessage sayHello(String who) {
        return new MyMessage().setMessage(String.format(
                "hello %s, it's %s",
                who, DateTime.now().toString("HH:mm:ss")));
    }
}

Developer Friendly





DEMO

Developer Friendly


Easy Setup
Fast startup
Auto compile
Play well with your IDE
Nice error reporting on JSON mapping errors
API Docs
Monitor
Factory UI
Easy debugging

Enterprise Ready


  • Pure Java
  • Available in Maven Central
  • Easily build with Maven / Ant+Ivy
  • Test with JUnit
  • Develop in your preferred IDE
  • Deploy in any servlet 2.5 container with Java 7
  • Easily embeddable (it's just a servlet)
  • Enterprise friendly Open Source License (ASL)

Cloud Ready

Deploy on
Any Java PAAS

  • Cloudbees
  • Heroku
  • Google App Engine
  • JElastic
  • CloudFoundry
  • ...

Cloud Ready

Deploy on
Any IAAS

  • AWS EC2
  • Google Compute Engine
  • OVH public cloud
  • your private cloud
  • ...

    Cloud demo


    Cloudbees

    https://run-eu.cloudbees.com/a/myaccount


    $ restx app new
    [...]
    $ mvn package
    $ bees app:deploy target/*.war -a myaccount/myapp

    RESTX w/ MongoDB

    a module based on jongo

    @Component @RestxResource
    public class CompanyResource {
        private final JongoCollection companies;
    
        public CompanyResource(
          @Named("companies") JongoCollection companies) {
            this.companies = companies;
        }
    
        @GET("/companies")
        public Iterable<Company> findCompanies() {
            return companies.get().find().as(Company.class);
        }
    }

    RESTX W/ MONGODB

    • uses Jackson for Mapping
      • symmetry between REST API and storage
      • can use views mechanism to include/exclude fields
    • tight integration with RESTX
      • support for RESTX specs
        • recording (capture states of collections used)
        • replay (setup DB for tests, fetch collections with data fixtures)
      • super easy to use

    RESTX Specs


    Specify your API behavior in format close to HTTP:
    title: should say hello
    given:
      - time: 2013-03-31T14:33:18.272+02:00
    wts:
      - when: GET message?who=xavier
        then: |      200 OK
          {"message":"hello xavier, it's 14:33:18"}

    RESTX Specs

    This can be used for:

    • integration tests
    • examples in API documentation
    • REST API mocking

    RESTX Specs


    can easily be recorded 



    capture:
    • system state (time, DB state, ...)
    • request
    • response

    Status


    Still in development but...

    deployed in production in 3 projects
    + 3 projects still in development

    a growing community
    • 2 committers
      • @xavierhanin
      • @fcamblor
    • 6 contributors

    Future

    1.0: target early 2014

    • API stabilization and more doc
    • better error reporting (esp. validation)
    • better API console


    Stronger Community

    Come and join!




    Thank you !


    Questions?

    Links

    http://www.ietf.org/rfc/rfc2616.txt
    https://github.com/andreineculau/know-your-http-well
    http://kellabyte.com/2011/09/04/clarifying-rest/
    http://www.restapitutorial.com/
    http://amzn.to/3V0qPn

    http://restx.io/
    Made with Slides.com