SlideShare uma empresa Scribd logo
1 de 291
Put your client and server to
     REST with JAX-RS
    Guilherme Silveira and Jan Algermissen
Guilherme Silveira
    Technical leader, Instructor
       @guilhermecaelum
guilherme.silveira@caelum.com.br
Guilherme Silveira
    Technical leader, Instructor
       @guilhermecaelum
guilherme.silveira@caelum.com.br
2002 guj.com.br
                                   2003 vraptor
                                   2004 caelumobjects.com
                                        xp, xstream
   Guilherme Silveira              2006 scrum
    Technical leader, Instructor
       @guilhermecaelum
                                   2009 restfulie, lean
guilherme.silveira@caelum.com.br
Guilherme Silveira
    Technical leader, Instructor
       @guilhermecaelum
guilherme.silveira@caelum.com.br
Guilherme Silveira
    Technical leader, Instructor
       @guilhermecaelum
guilherme.silveira@caelum.com.br
Training and Consulting



   Guilherme Silveira
    Technical leader, Instructor
       @guilhermecaelum
guilherme.silveira@caelum.com.br
a ge
              o Im
       y -N
  rr
So                       2002 Discovered REST
                         2005 1st pure REST project
                         2008 REST gaining momentum
  Jan Algermissen
  algermissen@acm.org    2009 NORD SC
      @algermissen
bank.com     calendar.com




travel.com   company.com
CORBA
heaven?
EJB
heaven?
SOAP
heaven?
what is REST?
what is the future
 of integration
 over the web?
what was REST?
Restful Web


              Services
Restful Web

create a saas account

                        Services
Restful Web

create a saas account


   freeze account
                        Services
Restful Web

create a saas account


   freeze account
                        Services

 reactivate account
Web




Restful         Services
Web
          http




Restful          Services
Web
           http

          port 80




Restful             Services
Web
           http

          port 80


      firewall heaven


Restful             Services
Web Services


Restful
Web Services

             xml, json
Restful
Web Services

              xml, json
Restful
             get, post, ...
Restful Web Services
          as of 2009




  But what about Hypermidia?
    What about consumers?
Restful Web Services
          as of 2009




  But what about Hypermidia?
    What about consumers?
   There is much more!
unresttrips.com: flight details



<?xml version="1.0" encoding="UTF-8" standalum="yes"?>
<flight>
  <information>
    <from>sao paulo</from>
    <to>seoul</to>
  </information>
  <value>900.00</value>
</flight>
service locator when integrating:
                        coupling++

                            unrest
                             pay

                     unresttrips


 guilherme
service locator when integrating:
                        coupling++

                            unrest
                             pay

                     unresttrips


 guilherme
resttrips.com: flight details



<?xml version="1.0" encoding="UTF-8" standalum="yes"?>
<flight>
  <information>
    <from>sao paulo</from>
    <to>seoul</to>
  </information>
  <value>900.00</value>
  <link rel="payment"
              href="http://resttrips.com/payment/custom"/
</flight>
resttrips.com: flight details



<?xml version="1.0" encoding="UTF-8" standalum="yes"?>
<flight>
  <information>
    <from>sao paulo</from>
    <to>seoul</to>
  </information>
  <value>900.00</value>
  <link rel="payment"
              href="http://resttrips.com/payment/custom"/
</flight>
resttrips.com: making the payment




flight = Client.at('http://resttrips.com/f/574XR4').get();

confirmation = flight.getLink("payment").
                  patch(cardInformation, value);
resttrips.com: making the payment




flight = Client.at('http://resttrips.com/f/574XR4').get();

confirmation = flight.getLink("payment").
                  patch(cardInformation, value);
resttrips.com: changing its payment provider


<?xml version="1.0" encoding="UTF-8" standalum="yes"?>
<flight>
  <information>
    <from>sao paulo</from>
    <to>seoul</to>
  </information>
  <value>900.00</value>
  <link rel="payment"
              href="http://paysite.com/custom"/>
</flight>
resttrips.com: changing its payment provider


<?xml version="1.0" encoding="UTF-8" standalum="yes"?>
<flight>
  <information>
    <from>sao paulo</from>
    <to>seoul</to>
  </information>
  <value>900.00</value>
  <link rel="payment"
              href="http://paysite.com/custom"/>
</flight>
dependency injection when integrating:

                             coupling--

                              restrips
                                pay

                        resttrips.com


   guilherme




                              paysite.com
dependency injection when integrating:

                             coupling--

                              restrips
                                pay

                        resttrips.com


   guilherme




                              paysite.com
trip = resource
        http://kayak.com/f/574XR4




payment = resource
        any_uri_unknown_at_compile_time
resttrips.com: sharing a trip


flight = Client.at('http://resttrips.com/f/574XR4').get();

confirmation = flight.getLink("payment").
                  patch(cardInformation, value/2);

// send the payment link to another part of the web

flight = Client.at('http://resttrips.com/f/574XR4').get();

confirmation = flight.getLink("payment").
                  patch(cardInformation, value/2);
resttrips.com: sharing a trip


flight = Client.at('http://resttrips.com/f/574XR4').get();

confirmation = flight.getLink("payment").
                  patch(cardInformation, value/2);

// send the payment link to another part of the web

flight = Client.at('http://resttrips.com/f/574XR4').get();

confirmation = flight.getLink("payment").
                  patch(cardInformation, value/2);
resttrips.com: sharing a trip


flight = Client.at('http://resttrips.com/f/574XR4').get();

confirmation = flight.getLink("payment").
                  patch(cardInformation, value/2);

// send the payment link to another part of the web

flight = Client.at('http://resttrips.com/f/574XR4').get();

confirmation = flight.getLink("payment").
                  patch(cardInformation, value/2);
resttrips.com: sharing a trip


flight = Client.at('http://resttrips.com/f/574XR4').get();

confirmation = flight.getLink("payment").
                  patch(cardInformation, value/2);

// send the payment link to another part of the web

flight = Client.at('http://resttrips.com/f/574XR4').get();

confirmation = flight.getLink("payment").
                  patch(cardInformation, value/2);
calendar: integrating my systems


myself = Client.at('http://users.calendar.com')
                                .with(auth).get();

myself.link("calendar").patch(flight.link("self"));
calendar: integrating my systems


myself = Client.at('http://users.calendar.com')
                                .with(auth).get();

myself.link("calendar").patch(flight.link("self"));
calendar: more examples



me.link("calendar").patch(link_to_birthday_list)
me.link("calendar").patch(link_to_hotel_reservation)
me.link("calendar").patch(link_to_trip_details)
so what?
so what?




Any update on the flight ==> reflects here
Any update on the hotel ==> reflects here
Any update on the meeting ==> reflects here
so what?



                                      r at e!
                               i nt eg
                       us e,
               ju st
      o n ’t
    d
Any update on the flight ==> reflects here
Any update on the hotel ==> reflects here
Any update on the meeting ==> reflects here
so what? that was just keeping an URI.
so what? that was just keeping an URI.




       Remove ==> Cancels the flight
       Remove ==> Cancels the reservation
       Remove ==> Emails your coworkers
so what? that was just keeping an URI.



                                         ro l!
                                    co nt
                          a li ze
                     en tr
                no tc
           do
       Remove ==> Cancels the flight
       Remove ==> Cancels the reservation
       Remove ==> Emails your coworkers
integration over the web




INTEGRATION is DECENTRALIZING the CONTROL
          delegating to multiple agents
              distributed systems
does our ‘rest’
sites in 2010 work
      this way?
so what? that was just keeping an URI.




       Remove ==> Cancels the flight
       Remove ==> Cancels the reservation
       Remove ==> Emails your coworkers
so what? that was just keeping an URI.




                                      a t?
                              fo rm
                      hi ch
               bu tw

       Remove ==> Cancels the flight
       Remove ==> Cancels the reservation
       Remove ==> Emails your coworkers
exercise
who is that guy?
who is that girl?
too easy, right? who is that little girl?
too easy, right? who is that little girl?




                                     ht er
                                da ug
                            y
                        notm
                     is
              s he
content without
semantic has no value!
so what?
so what?




micro formats, media types, rdf etc
so what?



                                  nk s!
                             er li
                          hyp
                  w ith
            ats
       fo rm
 ic ro
m

micro formats, media types, rdf etc
integration over the web
Put your server to REST
    leonard richardsons model
Server Maturity
              1 uri, 1 http verb

/services.do?action=install&...
Server Maturity
                  1 uri, 1 http verb

/services.do?action=install&...

@Path("/services")
public class Services {

  @GET
  public Response services(
    @QueryParam("action") String action) {

    ServiceFactory factory = new ServiceFactory();
    Service service = factory.getServiceFor(action);
    return service.execute();
  }

}
Server Maturity
                1 uri, 1 http verb


public class InstallService {

  public Response execute() {
    return Response.ok()
             .type("application/xml")
             .entity("<service>...</service>")
             .build();
  }

}
But?
1 uri, 1 http verb



/services.do?action=install&...



 I know them all beforehand.
1 uri, 1 http verb



/services.do?action=install&...




Any change will break all our clients!
a priori knowledge
a priori knowledge
        =
a priori knowledge
        =
    coupling++
Server Maturity
           Multiple uris, 1 http verb

/install?...
Server Maturity
             Multiple uris, 1 http verb

/install?...

 @Path("/services")
 public class Services {

   @GET @Path("install")
   public Response install() {
     return new InstallService().execute();
   }

   @GET @Path("uninstall")
   public Response uninstall() {
     return new UninstallService().execute();
   }
but...
GET hell


GET should not imply in
  undesireable effects
POST hell


GET could help us with
        cache!
Server Maturity
  Multiple uris, multiple verbs




         POST /cloud
 GET /cloud/1547437/software
POST /cloud/1547437/software
rails + restfulie
  rubyonrails.org
rails + restfulie
                   rubyonrails.org
class SoftwaresController < ApplicationController
  
  acts_as_restfulie
  respond_to :xml, :json
  
  def create
    @item = Item.create(params[:item])
    respond_with @item, :status => :created
  end
  
  def show
    @item = Item.find(params[:id])
    respond_with @item
  end
end
Vraptor
vraptor.org/en
Vraptor
                     vraptor.org/en
@Resource
public class SoftwareResource {

  public void install() {
    Software software = SoftwareRepository.register
                                            (software);
    response.created(software);
  }

  public void uninstall() {
    response.deleted(software);
  }

}
JAX-RS

@Path("/softwares")
public class SoftwareResource {

  @POST @Consumes("application/xml")
  public Response install(Software software) {
    software = SoftwareRepository.register(software);
    long id = software.getId();
    URI uri = UriBuilder.fromPath("/softwares/" + id)
                                       .build();
    software.install();
    return Response.created(uri).build();
  }
JAX-RS


  @DELETE @Path("{id}")
  public Response uninstall(@PathParam("id") Long id) {
    Software software = SoftwareRepository.retrieve(id);
    software.uninstall();
    return Response.ok().build();
  }
Uniform Interface++
   Resources++
Http verbs example
POST creates

PUT replaces

PATCH updates

DELETE removes

GET retrieves

OPTIONS tells me what i can do

...
Is a Restful service
   a cute CRUD?
yes
but there is more!
hypermedia
  enter amazon.com
hypermedia
  enter amazon.com

    search (GET)
hypermedia
    enter amazon.com

      search (GET)




 create a payment (POST)
hypermedia
    enter amazon.com

      search (GET)

      search (GET)



 create a payment (POST)
hypermedia
    enter amazon.com

      search (GET)

      search (GET)

  create a basket (POST)

 create a payment (POST)
hypermedia
    enter amazon.com       follow links


      search (GET)

      search (GET)

  create a basket (POST)

 create a payment (POST)
hypermedia
    enter amazon.com       follow links


      search (GET)

      search (GET)
                            fill forms
  create a basket (POST)

 create a payment (POST)
Cloud API

GET /user/15    retrieves an user
Cloud API

   GET /user/15         retrieves an user


follow GET machines   accesses its machines
Cloud API

   GET /user/15          retrieves an user


follow GET machines   accesses its machines


  follow POST self    installs a new machine
Cloud API

   GET /user/15          retrieves an user


follow GET machines   accesses its machines


  follow POST self    installs a new machine

follow POST payment         pay for it
retrieves an user


$ curl http://localhost:9998/user/574 -i
HTTP/1.1 200 OK
...
user

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
    <link rel="machines" href="/user/574/machines"/>
    <name>guilherme silveira</name>
    <website>www.caelum.com.br</site>
   <link rel="payment" href="/payment/custom"/>
    ...
</user>
user

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
    <link rel="machines" href="/user/574/machines"/>
    <name>guilherme silveira</name>
    <website>www.caelum.com.br</site>
   <link rel="payment" href="/payment/custom"/>
    ...
</user>
maschine maschine maschine



$ curl http://localhost:9998/user/574/machines -i
HTTP/1.1 200 OK
Content-Type: application/xml
maschine
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<machines xmlns:ns2="http://www.w3.org/2005/Atom">
  <machine>
    <ns2:link rel="self" href="/user/574/machines/1"/>
    <ns2:link rel="software" href="/machines1/softwares"/>
    <id>1</id>
    <host>www.caelum.com.br</host>
    <softwares>
      <software>
        <id>1234</id>
        <ns2:link rel="self" href="/softwares/1234"/>
      </software>
    </softwares>
  </machine>
</machines>
maschine
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<machines xmlns:ns2="http://www.w3.org/2005/Atom">
  <machine>
    <ns2:link rel="self" href="/user/574/machines/1"/>
    <ns2:link rel="software" href="/machines1/softwares"/>
    <id>1</id>
    <host>www.caelum.com.br</host>
    <softwares>
      <software>
        <id>1234</id>
        <ns2:link rel="self" href="/softwares/1234"/>
      </software>
    </softwares>
  </machine>
</machines>
payment


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
    <link rel="machines" href="/user/574/machines"/>
    <name>guilherme silveira</name>
    <website>www.caelum.com.br</site>
   <link rel="payment" href="/payment/custom"/>
    ...
</user>
payment


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
    <link rel="machines" href="/user/574/machines"/>
    <name>guilherme silveira</name>
    <website>www.caelum.com.br</site>
   <link rel="payment" href="/payment/custom"/>
    ...
</user>
#buthow?
@XmlRootElement
@XmlType(propOrder= {"id", "host", "softwares", "links"})
public class Machine {
  private final all variables here;

  @XmlElement(name="link", namespace="http://www.w3.org/2005/Atom")
  public List<Link> getLinks() {
    return Arrays.asList(
      Link.to("/machines/" + getId(), "self"),
      Link.to("/machines/" + getId() + "/softwares", "softwares")
    );
  }

  @XmlElementWrapper(name="softwares")
  @XmlElement(name="software")
  public List<Software> getSoftwares() {
    return softwares;
  }

  public void install(Software software) {
    getSoftwares().add(software);
  }

  public void uninstall(Software software) {
    getSoftwares().remove(software);
  }

}                                              Machine.java
@XmlRootElement
@XmlType(propOrder= {"id", "host", "softwares", "links"})
public class Machine {
  private final all variables here;

  @XmlElement(name="link", namespace="http://www.w3.org/2005/Atom")
  public List<Link> getLinks() {
    return Arrays.asList(
      Link.to("/machines/" + getId(), "self"),
      Link.to("/machines/" + getId() + "/softwares", "softwares")
    );
  }

  @XmlElementWrapper(name="softwares")
  @XmlElement(name="software")
  public List<Software> getSoftwares() {
    return softwares;
  }

  public void install(Software software) {
    getSoftwares().add(software);
  }

  public void uninstall(Software software) {
    getSoftwares().remove(software);
  }

}                                              Machine.java
@Path("/machines")
public class MachineResource {        MachineResource
  @Path("{id}/softwares")
  public SoftwareResource softwares(@PathParam("id") Long id) {
    Machine machine = new MachineRepository().retrieve(id);
    if (machine != null) {
      SoftwareResource softwareResource = new SoftwareResource();

 
 softwareResource.setMachine(machine);
      return softwareResource;
    }
    throw new WebApplicationException(404);

 }


   @POST @Consumes("application/xml")

   public Response create(Machine machine) {

   
 Long id = new MachineRepository().save(machine);

   
 return Response.created(UriBuilder.fromPath("/" + id).build()).build();

   }


   @GET @Path("{id}")

   @Produces("application/xml")

   public Machine show(@PathParam("id") Long id) {

   
 return new MachineRepository().retrieve(id);

   }


   @GET

   @Produces("application/xml")

   public Machines list() {

   
 Machines machines = new Machines();

   
 machines.setMachine(new MachineRepository().list());

   
 return machines;
@Path("/machines")
public class MachineResource {        MachineResource
  @Path("{id}/softwares")
  public SoftwareResource softwares(@PathParam("id") Long id) {
    Machine machine = new MachineRepository().retrieve(id);
    if (machine != null) {
      SoftwareResource softwareResource = new SoftwareResource();

 
 softwareResource.setMachine(machine);
      return softwareResource;
    }
    throw new WebApplicationException(404);

 }


   @POST @Consumes("application/xml")

   public Response create(Machine machine) {

   
 Long id = new MachineRepository().save(machine);

   
 return Response.created(UriBuilder.fromPath("/" + id).build()).build();

   }


   @GET @Path("{id}")

   @Produces("application/xml")

   public Machine show(@PathParam("id") Long id) {

   
 return new MachineRepository().retrieve(id);

   }


   @GET

   @Produces("application/xml")

   public Machines list() {

   
 Machines machines = new Machines();

   
 machines.setMachine(new MachineRepository().list());

   
 return machines;
Server Model
according to
Leonard Richardson, 2008




                           one uri + one verb
Server Model
according to
Leonard Richardson, 2008




                               Ugly
                           one uri + one verb
Server Model
according to
Leonard Richardson, 2008




                           multiple
                            uris



                            one uri + one verb
Server Model
according to
Leonard Richardson, 2008



                                      Less ugly
                           multiple
                            uris



                            one uri + one verb
Server Model
according to
Leonard Richardson, 2008


                                       multiple
                                        verbs
                           multiple
                            uris



                            one uri + one verb
Server Model
according to
Leonard Richardson, 2008
                           cute CRUD
                                       multiple
                                        verbs
                           multiple
                            uris



                            one uri + one verb
Server Model                      rest
according to
Leonard Richardson, 2008        hypermedia


                                       multiple
                                        verbs
                           multiple
                            uris



                            one uri + one verb
JAX-RS wishlist

  VRaptor and Restfulie
examples
vraptor.org/en
1. conventions?


@Path("/services")
public class Services {

  @GET
  public Response services(
    @QueryParam("action") String action) {

    ServiceFactory factory = new ServiceFactory();
    Service service = factory.getServiceFor(action);
    return service.execute();
  }

}
Convention over Configuration


@Resource
public class Services {
	
	 private final ServiceFactory factory;
	
	 public Services(ServiceFactory factory) {
	 	 this.factory = factory;
	 }

	 public void services(String action) {
	 	 factory.getServiceFor(action).execute();
	 }

}
do you want to avoid
    copy+paste?
yes!
yes!
2. TDD: hard to test
@Path("/products")
public class Products {
                                   coupled to the
  @GET                            implementation
  public Response create(
    @QueryParam("what") String what) {

    // persists
    return Response.ok()
             .type("application/xml")
             .entity("<product>...</product>")
             .build();
  }

}
TDD: mock it
                                 coupled to the interface
                                        couple--

@Resource
public class Services {
	
	 private final Response response;
	
	 public Services(Response response) {
	 	 this.response = response;
	 }

	 public void services(String action) {
	 	 response.getServiceFor(action).execute();
	 }

}
TDD: mock it
                                 coupled to the interface
                                        couple--

@Resource
public class Services {
	
	 private final Response response;
	
	 public Services(Response response) {
	 	 this.response = response;
	 }

	 public void services(String action) {
	 	 response.getServiceFor(action).execute();
	 }

}
3. Content negotiation by hand

@Path("/softwares")
public class SoftwareResource {

  @POST @Consumes("application/xml")
  public Response install(Software software) {
    software = SoftwareRepository.register(software);
    long id = software.getId();
    URI uri = UriBuilder.fromPath("/softwares/" + id)
                                       .build();
    software.install();
    return Response.created(uri).build();
  }
Let us do it for you.


@Resource
public class SoftwareResource {

  @Post @Consumes
  public void install(Software software) {
    software = SoftwareRepository.register(software);
    response.created(software);
  }

}
Let us do it for you.


@Resource
public class SoftwareResource {

  @Post @Consumes
  public void install(Software software) {
    software = SoftwareRepository.register(software);
    response.created(software);
  }

}
4. URI coupling

                                   writing the URI once


...

  @GET @Path("/softwares/{id}")
  public Response install(@QueryParam("id") Software
software) {
    // ...
  }
4. URI coupling
                                  writing the URI again
                                       several times
@Path("/softwares")
public class SoftwareResource {

  @POST @Consumes("application/xml")
  public Response install(Software software) {
    software = SoftwareRepository.register(software);
    long id = software.getId();
    URI uri = UriBuilder.fromPath("/softwares/" + id)
                                       .build();
    software.install();
    return Response.created(uri).build();
  }
4. URI coupling
                                            code
@Path("/softwares")
public class SoftwareResource {

  @POST @Consumes("application/xml")
  public Response install(Software software) {
    software = SoftwareRepository.register(software);
    long id = software.getId();
    URI uri = UriBuilder.fromPath("/softwares/" + id)
                                       .build();
    software.install();
    return Response.created(uri).build();
  }
ZERO uri replication


@Resource
public class SoftwareResource {

  @Post @Consumes
  public void install(Software software) {
    // ...
    response.use(SoftwareResource.class).show(software);
  }

}
ZERO uri replication


@Resource
public class SoftwareResource {

  @Post @Consumes
  public void install(Software software) {
    // ...
    response.use(SoftwareResource.class).show(software);
  }

}
5. Parameter list


@Path("/machines")
public class MachineResource {

  @Path("{id}/softwares")
  public SoftwareResource softwares(@PathParam("id") Long id) {
    Machine machine = new MachineRepository().retrieve(id);
    if (machine == null) {
      throw new WebApplicationException(404);
    }
    // ...

 }


}
Yes, we can do it.


@Resource
public class MachineResource {

  @Post ("{m.id}/softwares")
  public SoftwareResource softwares(Machine m) {
    Machine machine = new MachineRepository().retrieve(m
    // ...

 }

}



              parameter converter chain of responsability
Yes, we can do it.


@Resource
public class MachineResource {

  @Post ("{m.id}/softwares")
  public SoftwareResource softwares(Machine m) {
    Machine machine = new MachineRepository().retrieve(m
    // ...

 }

}



              parameter converter chain of responsability
example
restfulie.caelumobjects.com
Response response = client.at
    ("http://localhost:9998/user/574").get();




        6. Client internal DSLs
Response response = client.at
    ("http://localhost:9998/user/574").get();

User user = response.getResource();
System.out.println("user: " + user.getName());




        6. Client internal DSLs
User user = response.getResource();
System.out.println("user: " + user.getName());

Link link = resource(user).getLink("machine");
response = link.follow().post(new Machine());
Link link = resource(user).getLink("machine");
response = link.follow().post(new Machine());


double amount = resource(user).refresh().
                                        getAmountDue();
double amount = resource(user).refresh().
                                        getAmountDue();


link = resource(user).getLink("payment");
Payment payment = new Payment(amount);
response = link.follow().post(payment);
link = resource(user).getLink("payment");
Payment payment = new Payment(amount);
response = link.follow().post(payment);

System.out.println("payment completed");
link = resource(user).getLink("payment");
Payment payment = new Payment(amount);
response = link.follow().post(payment);

System.out.println("payment completed");




      i was looking for a DSL
       and i did not know it!
Putting JAX-RS Clients to
          REST
“Jersey View Client”

• Developed early 2010
• w/ Paul Sandoz (@paulsandoz)
• To-be Jersey RESTful client API
• Feedback welcome!
Goals

• Encourage RESTful client side programming
• Natural coding model
• Resemble JAX-RS annotation style
LEARN FROM
WEB BROWSER
HTTP Request
Web Browser Tasks
Web Browser Tasks
• GET resource after user enters URL
Web Browser Tasks
• GET resource after user enters URL
• Build up Web page
Web Browser Tasks
• GET resource after user enters URL
• Build up Web page
• Show informatin (title, content)
Web Browser Tasks
• GET resource after user enters URL
• Build up Web page
• Show informatin (title, content)
• Expose links and forms
Web Browser Tasks
• GET resource after user enters URL
• Build up Web page
• Show informatin (title, content)
• Expose links and forms
• Act upon link activation or form
  submission
A Web Page
A Web Page
• Has a location
A Web Page
• Has a location
• Build from response(s)
A Web Page
• Has a location
• Build from response(s)
• Holds application state
A Web Page
• Has a location
• Build from response(s)
• Holds application state
• Exposes application state
A Web Page
• Has a location
• Build from response(s)
• Holds application state
• Exposes application state
• Exposes links and forms
A Web Page
• Has a location
• Build from response(s)
• Holds application state
• Exposes application state
• Exposes links and forms
• Assumptions
GENERALIZE
FROM HERE
User Agent
User Agent

• Use entry URI to start application
User Agent

• Use entry URI to start application
• Build up application state from response(s)
User Agent

• Use entry URI to start application
• Build up application state from response(s)
• Make state available
User Agent

• Use entry URI to start application
• Build up application state from response(s)
• Make state available
• Make hypermedia controls activatable
User Agent

• Use entry URI to start application
• Build up application state from response(s)
• Make state available
• Make hypermedia controls activatable
• Construct request upon control activation
A View
A View
• Bound to resource
A View
• Bound to resource
• Build from response(s)
A View
• Bound to resource
• Build from response(s)
• Holds application state
A View
• Bound to resource
• Build from response(s)
• Holds application state
• Exposes application state
A View
• Bound to resource
• Build from response(s)
• Holds application state
• Exposes application state
• Enables activation of controls
A View
• Bound to resource
• Build from response(s)
• Holds application state
• Exposes application state
• Enables activation of controls
• Bundles Assumptions
View:
Combination of state
 and assumptions,
  bound to a URI
So where is the
  difference?
Browser:
A single kind of
      view!
That’s ok in
Browser-land
Can’t do machine REST
with a single kind of
         view
Not just one kind of
  application state
Atom Pub

• Service view
• Feed view
• Entry View
Our Example

• User account view
• Machine View
• Invoice View
Client Side
   API?
Use classes to
represent kinds of
      views
A view class for a Web Page View
WebPageView pageView = client.view(
     “https://twitter.com/signup”,WebPageView.class);

Form form = page.getFormsByIndex(0);
form.name = “John”;
form.submit();
View Classes
View Classes
• Relate instance to resource
View Classes
• Relate instance to resource
• Handle response
View Classes
• Relate instance to resource
• Handle response
• Build up application state
View Classes
• Relate instance to resource
• Handle response
• Build up application state
• Expose application state
View Classes
• Relate instance to resource
• Handle response
• Build up application state
• Expose application state
• Expose hypermedia controls
View Classes
• Relate instance to resource
• Handle response
• Build up application state
• Expose application state
• Expose hypermedia controls
• Perform requests upon control activation
View Classes
• Relate instance to resource
• Handle response
• Build up application state
• Expose application state
• Expose hypermedia controls
• Perform requests upon control activation
• Bundle assumptions
A class for account views

URI ACCOUNT_URI = new URI(
                    “http://example.org/saas/user/john/account”);
Client client = new Client();

// Create view instance bound to a URI
AccountView av = client.view(ACCOUNT_URI, AccountView.class);

// Access application state held by view

// Invoke controls exposed by view
A Media Type
GET /saas/user/john/account

200 Ok
Content-Type: application/saas

<account>
  <machines href=”./machines”
    accept=”application/saas;type=machine”/>
  <payments href=”./payments”
    accept=”application/saas;type=payment”/>
  <userData>
    <name>John Doe</name>
    ...
  </userData>
</account>
public class AccountView {
  // hold state
  private ViewResource machineCollection;
  private ViewResource paymentProcessor;
  private String userName;

    @GET @Consumes(“application/saas;type=account”)
    public void build(Account account) {
      // build state from response
    }

    public String getUserName() { return userName; }

    // <machines href=””/> control exposed
    public CreatedMachineView addMachine(Machine machine) {
       return machineCollection.post(machine,
                          CreatedMachineView.class)
    }

    // <payments href=””/> control exposed
    public void submitPayment(Payment payment) {
      paymentProcessor.post(payment);
    }
}
public class AccountView {
  // hold state
  private ViewResource machineCollection;
  private ViewResource paymentProcessor;
  private String userName;

    @GET @Consumes(“application/saas;type=account”)
    public void build(Account account) {
      // build state from response
    }

    public String getUserName() { return userName; }

    // <machines href=””/> control exposed
    public CreatedMachineView addMachine(Machine machine) {
       return machineCollection.post(machine,
                          CreatedMachineView.class)
    }

    // <payments href=””/> control exposed
    public void submitPayment(Payment payment) {
      paymentProcessor.post(payment);
    }
}
public class AccountView {
  // hold state
  private ViewResource machineCollection;
  private ViewResource paymentProcessor;
  private String userName;

    @GET @Consumes(“application/saas;type=account”)
    public void build(Account account) {
      // build state from response
    }

    public String getUserName() { return userName; }

    // <machines href=””/> control exposed
    public CreatedMachineView addMachine(Machine machine) {
       return machineCollection.post(machine,
                          CreatedMachineView.class)
    }

    // <payments href=””/> control exposed
    public void submitPayment(Payment payment) {
      paymentProcessor.post(payment);
    }
}
public class AccountView {
  // hold state
  private ViewResource machineCollection;
  private ViewResource paymentProcessor;
  private String userName;

    @GET @Consumes(“application/saas;type=account”)
    public void build(Account account) {
      // build state from response
    }

    public String getUserName() { return userName; }

    // <machines href=””/> control exposed
    public CreatedMachineView addMachine(Machine machine) {
       return machineCollection.post(machine,
                          CreatedMachineView.class)
    }

    // <payments href=””/> control exposed
    public void submitPayment(Payment payment) {
      paymentProcessor.post(payment);
    }
}
public class AccountView {
  // hold state
  private ViewResource machineCollection;
  private ViewResource paymentProcessor;
  private String userName;

    @GET @Consumes(“application/saas;type=account”)
    public void build(Account account) {
      // build state from response
    }

    public String getUserName() { return userName; }

    // <machines href=””/> control exposed
    public CreatedMachineView addMachine(Machine machine) {
       return machineCollection.post(machine,
                          CreatedMachineView.class)
    }

    // <payments href=””/> control exposed
    public void submitPayment(Payment payment) {
      paymentProcessor.post(payment);
    }
}
public class AccountView {
  // hold state
  private ViewResource machineCollection;
  private ViewResource paymentProcessor;
  private String userName;

    @GET @Consumes(“application/saas;type=account”)
    public void build(Account account) {
      // build state from response
    }

    public String getUserName() { return userName; }

    // <machines href=””/> control exposed
    public CreatedMachineView addMachine(Machine machine) {
       return machineCollection.post(machine,
                          CreatedMachineView.class)
    }

    // <payments href=””/> control exposed
    public void submitPayment(Payment payment) {
      paymentProcessor.post(payment);
    }
}
Choosing a certain
view class to handle a
response manifests an
     assumption!
Using View Classes
AccountView accountView = client.view(
                         ACCOUNT_URI,AccountView.class);
LOG.info(“Working on account for “ +
                         accountView.getUserName());

Machine machine = newMachine();
CreatedMachineView cmv = accountView.addMachine(machine);
LOG.info("New machine is at: " + cmv.getLocation());

InvoiceView invoiceView = cmv.getInvoiceView();
Payment payment = new Payment(invoiceView.getAmount(),
                          myCreditCardData);
accountView.makePayment(payment);
Using View Classes
AccountView accountView = client.view(
                         ACCOUNT_URI,AccountView.class);
LOG.info(“Working on account for “ +
                         accountView.getUserName());

Machine machine = newMachine();
CreatedMachineView cmv = accountView.addMachine(machine);
LOG.info("New machine is at: " + cmv.getLocation());

InvoiceView invoiceView = cmv.getInvoiceView();
Payment payment = new Payment(invoiceView.getAmount(),
                          myCreditCardData);
accountView.makePayment(payment);
Using View Classes
AccountView accountView = client.view(
                         ACCOUNT_URI,AccountView.class);
LOG.info(“Working on account for “ +
                         accountView.getUserName());

Machine machine = newMachine();
CreatedMachineView cmv = accountView.addMachine(machine);
LOG.info("New machine is at: " + cmv.getLocation());

InvoiceView invoiceView = cmv.getInvoiceView();
Payment payment = new Payment(invoiceView.getAmount(),
                          myCreditCardData);
accountView.makePayment(payment);
Using View Classes
AccountView accountView = client.view(
                         ACCOUNT_URI,AccountView.class);
LOG.info(“Working on account for “ +
                         accountView.getUserName());

Machine machine = newMachine();
CreatedMachineView cmv = accountView.addMachine(machine);
LOG.info("New machine is at: " + cmv.getLocation());

InvoiceView invoiceView = cmv.getInvoiceView();
Payment payment = new Payment(invoiceView.getAmount(),
                          myCreditCardData);
accountView.makePayment(payment);
Using View Classes
AccountView accountView = client.view(
                         ACCOUNT_URI,AccountView.class);
LOG.info(“Working on account for “ +
                         accountView.getUserName());

Machine machine = newMachine();
CreatedMachineView cmv = accountView.addMachine(machine);
LOG.info("New machine is at: " + cmv.getLocation());

InvoiceView invoiceView = cmv.getInvoiceView();
Payment payment = new Payment(invoiceView.getAmount(),
                          myCreditCardData);
accountView.makePayment(payment);
Using View Classes
AccountView accountView = client.view(
                         ACCOUNT_URI,AccountView.class);
LOG.info(“Working on account for “ +
                         accountView.getUserName());

Machine machine = newMachine();
CreatedMachineView cmv = accountView.addMachine(machine);
LOG.info("New machine is at: " + cmv.getLocation());

InvoiceView invoiceView = cmv.getInvoiceView();
Payment payment = new Payment(invoiceView.getAmount(),
                          myCreditCardData);
accountView.makePayment(payment);
Using View Classes
AccountView accountView = client.view(
                         ACCOUNT_URI,AccountView.class);
LOG.info(“Working on account for “ +
                         accountView.getUserName());

Machine machine = newMachine();
CreatedMachineView cmv = accountView.addMachine(machine);
LOG.info("New machine is at: " + cmv.getLocation());

InvoiceView invoiceView = cmv.getInvoiceView();
Payment payment = new Payment(invoiceView.getAmount(),
                          myCreditCardData);
accountView.makePayment(payment);
Using View Classes
AccountView accountView = client.view(
                         ACCOUNT_URI,AccountView.class);
LOG.info(“Working on account for “ +
                         accountView.getUserName());

Machine machine = newMachine();
CreatedMachineView cmv = accountView.addMachine(machine);
LOG.info("New machine is at: " + cmv.getLocation());

InvoiceView invoiceView = cmv.getInvoiceView();
Payment payment = new Payment(invoiceView.getAmount(),
                          myCreditCardData);
accountView.makePayment(payment);
Things to Note
Things to Note
• Think of view like of browser window
Things to Note
• Think of view like of browser window
• Can keep them around, go back, use any
  time
Things to Note
• Think of view like of browser window
• Can keep them around, go back, use any
  time
• Handle for application state
Things to Note
• Think of view like of browser window
• Can keep them around, go back, use any
  time
• Handle for application state
• View class is single point of code
Things to Note
• Think of view like of browser window
• Can keep them around, go back, use any
  time
• Handle for application state
• View class is single point of code
• Bundles code and expectations
Things to Note
• Think of view like of browser window
• Can keep them around, go back, use any
  time
• Handle for application state
• View class is single point of code
• Bundles code and expectations
• Views classes used define application
thank you
Presentation Online


http://slidesha.re/put_them_to_rest
After-Talk Discussion

Come and discuss RESTfulie and Jersey View
Client.
The golden rule
In a world with serious
        issues
In a world with serious
        issues
In a world with serious
        issues
In a world with serious
        issues
What is the magical
    solution?
sunday in the park


“Ah, yes, a similar thing happens all the time
when flaying frisbee in the park with my dog.
When I throw the frisbee and the dog tries to
catch it in his teeth, everyone seems to be
happy.”
sunday in the park


“However, when the dog tries to throw the
frisbee and I try to catch it in my teeth,
it just doesn't seem to work well for either of
us.”



                     Roy Fielding, REST creator
If JMS does not fit your
problem, do not try to fit your
     solution within JMS.
If SOA does not fit your
problem, do not try to fit your
     solution within SOA.
If REST does not fit your
problem, do not try to fit your
     solution within REST.
finally
The golden rule

         If * does not fit
          your problem,
         do not try to fit
          your solution
              within *.
code samples


Lucas Cavalcanti
(java server)
@lucascs


           Anderson Leite (ruby)
               @anderson_leite
Further reading
Further reading
Roy Fielding dissertation
Further reading
Roy Fielding dissertation

Rest in Practice, Jim Webber and others
Further reading
Roy Fielding dissertation

Rest in Practice, Jim Webber and others

Restful Webservices Cookbook, Subbu Allamaraju
Further reading
Roy Fielding dissertation

Rest in Practice, Jim Webber and others

Restful Webservices Cookbook, Subbu Allamaraju

Restful Web Services, Richardson and Ruby
Further reading
Roy Fielding dissertation

Rest in Practice, Jim Webber and others

Restful Webservices Cookbook, Subbu Allamaraju

Restful Web Services, Richardson and Ruby

JAX-RS specification
Further reading
Roy Fielding dissertation

Rest in Practice, Jim Webber and others

Restful Webservices Cookbook, Subbu Allamaraju

Restful Web Services, Richardson and Ruby

JAX-RS specification

Infoq articles on REST
Further reading
Roy Fielding dissertation

Rest in Practice, Jim Webber and others

Restful Webservices Cookbook, Subbu Allamaraju

Restful Web Services, Richardson and Ruby

JAX-RS specification

Infoq articles on REST

Restfulie guide
Jersey related
Jersey related
Jersey related posts
Jersey related
Jersey related posts

  http://www.nordsc.com/blog/?cat=28
Jersey related
Jersey related posts

  http://www.nordsc.com/blog/?cat=28

Repository
Jersey related
Jersey related posts

  http://www.nordsc.com/blog/?cat=28

Repository

  https://jersey.dev.java.net/
Jersey related
Jersey related posts

  http://www.nordsc.com/blog/?cat=28

Repository

  https://jersey.dev.java.net/

Presentation
Jersey related
Jersey related posts

  http://www.nordsc.com/blog/?cat=28

Repository

  https://jersey.dev.java.net/

Presentation

  http://www.nordsc.com/presentations/j1/
Interviews and
 Presentations
Interviews and
             Presentations
Stefan Tilkov interview on InfoQ
Interviews and
             Presentations
Stefan Tilkov interview on InfoQ

  http://bit.ly/9RUXKL
Interviews and
             Presentations
Stefan Tilkov interview on InfoQ

  http://bit.ly/9RUXKL

Leonard Richardson’s presentation at QCon
Interviews and
             Presentations
Stefan Tilkov interview on InfoQ

  http://bit.ly/9RUXKL

Leonard Richardson’s presentation at QCon

  http://bit.ly/dj2W66
Interviews and
             Presentations
Stefan Tilkov interview on InfoQ

  http://bit.ly/9RUXKL

Leonard Richardson’s presentation at QCon

  http://bit.ly/dj2W66

Martin Fowler on REST
Interviews and
              Presentations
Stefan Tilkov interview on InfoQ

  http://bit.ly/9RUXKL

Leonard Richardson’s presentation at QCon

  http://bit.ly/dj2W66

Martin Fowler on REST

  http://bit.ly/bx61ci
Interviews and
 Presentations
Interviews and
             Presentations
Ian Robinson and Jim Webber interview
Interviews and
             Presentations
Ian Robinson and Jim Webber interview

 http://bit.ly/aEuzj3
Interviews and
             Presentations
Ian Robinson and Jim Webber interview

 http://bit.ly/aEuzj3

Jan Algermissen classification
Interviews and
             Presentations
Ian Robinson and Jim Webber interview

 http://bit.ly/aEuzj3

Jan Algermissen classification

 http://bit.ly/cycFBF
Interviews and
              Presentations
Ian Robinson and Jim Webber interview

  http://bit.ly/aEuzj3

Jan Algermissen classification

  http://bit.ly/cycFBF

Guilherme Silveira on REST clients
Interviews and
              Presentations
Ian Robinson and Jim Webber interview

  http://bit.ly/aEuzj3

Jan Algermissen classification

  http://bit.ly/cycFBF

Guilherme Silveira on REST clients

  http://bit.ly/aHCglv
code samples
code samples
JAX-RS
code samples
JAX-RS

 http://jcp.org/en/jsr/detail?id=311
code samples
JAX-RS

  http://jcp.org/en/jsr/detail?id=311

Rails
code samples
JAX-RS

  http://jcp.org/en/jsr/detail?id=311

Rails

  http://rubyonrails.org
code samples
JAX-RS

  http://jcp.org/en/jsr/detail?id=311

Rails

  http://rubyonrails.org

Restfulie
code samples
JAX-RS

  http://jcp.org/en/jsr/detail?id=311

Rails

  http://rubyonrails.org

Restfulie

  http://restfulie.caelumobjects.com
code samples
JAX-RS

  http://jcp.org/en/jsr/detail?id=311

Rails

  http://rubyonrails.org

Restfulie

  http://restfulie.caelumobjects.com

VRaptor
code samples
JAX-RS

  http://jcp.org/en/jsr/detail?id=311

Rails

  http://rubyonrails.org

Restfulie

  http://restfulie.caelumobjects.com

VRaptor

  http://vraptor.org/en

Mais conteúdo relacionado

Destaque

Equipes ágeis em 2012 - Lições aprendidas
Equipes ágeis em 2012 - Lições aprendidasEquipes ágeis em 2012 - Lições aprendidas
Equipes ágeis em 2012 - Lições aprendidas
Guilherme Silveira
 
REpresentational State Transfer
REpresentational State TransferREpresentational State Transfer
REpresentational State Transfer
Vladimir Tsukur
 

Destaque (20)

Devise
DeviseDevise
Devise
 
Software de qualidade e qualidade de código
Software de qualidade e qualidade de códigoSoftware de qualidade e qualidade de código
Software de qualidade e qualidade de código
 
Rest workflows
Rest workflowsRest workflows
Rest workflows
 
SPDY
SPDYSPDY
SPDY
 
Rest clients
Rest clientsRest clients
Rest clients
 
O grandiosismo dos loucos - Agile Brazil 2011, Cecilia Fernandes e Guilherme ...
O grandiosismo dos loucos - Agile Brazil 2011, Cecilia Fernandes e Guilherme ...O grandiosismo dos loucos - Agile Brazil 2011, Cecilia Fernandes e Guilherme ...
O grandiosismo dos loucos - Agile Brazil 2011, Cecilia Fernandes e Guilherme ...
 
Using the web for real
Using the web for realUsing the web for real
Using the web for real
 
Depois de Scrum e XP: não pare de aprender, não pare de inovar
Depois de Scrum e XP: não pare de aprender, não pare de inovarDepois de Scrum e XP: não pare de aprender, não pare de inovar
Depois de Scrum e XP: não pare de aprender, não pare de inovar
 
REST
RESTREST
REST
 
Introduction to JAX-RS
Introduction to JAX-RSIntroduction to JAX-RS
Introduction to JAX-RS
 
Smart Building Automation using Heterogeneous Wireless Sensor Networks (in gr...
Smart Building Automation using Heterogeneous Wireless Sensor Networks (in gr...Smart Building Automation using Heterogeneous Wireless Sensor Networks (in gr...
Smart Building Automation using Heterogeneous Wireless Sensor Networks (in gr...
 
Rest clients
Rest clientsRest clients
Rest clients
 
Deploy continuo, integraçao continua não basta
Deploy continuo, integraçao continua não bastaDeploy continuo, integraçao continua não basta
Deploy continuo, integraçao continua não basta
 
Arquitetura: chega de mesmice
Arquitetura: chega de mesmiceArquitetura: chega de mesmice
Arquitetura: chega de mesmice
 
REST Methodologies
REST MethodologiesREST Methodologies
REST Methodologies
 
Equipes ágeis em 2012 - Lições aprendidas
Equipes ágeis em 2012 - Lições aprendidasEquipes ágeis em 2012 - Lições aprendidas
Equipes ágeis em 2012 - Lições aprendidas
 
REST overview
REST overviewREST overview
REST overview
 
SPDY - or maybe HTTP2.0
SPDY - or maybe HTTP2.0SPDY - or maybe HTTP2.0
SPDY - or maybe HTTP2.0
 
Um produto por semana
Um produto por semanaUm produto por semana
Um produto por semana
 
REpresentational State Transfer
REpresentational State TransferREpresentational State Transfer
REpresentational State Transfer
 

Semelhante a Put your client and server to rest - Javaone

Satellite Apps around the Cloud: Integrating your infrastructure with JIRA St...
Satellite Apps around the Cloud: Integrating your infrastructure with JIRA St...Satellite Apps around the Cloud: Integrating your infrastructure with JIRA St...
Satellite Apps around the Cloud: Integrating your infrastructure with JIRA St...
Atlassian
 
How dorma+kaba leverages and deploys on CloudFoundry - CloudFoundry Summit Eu...
How dorma+kaba leverages and deploys on CloudFoundry - CloudFoundry Summit Eu...How dorma+kaba leverages and deploys on CloudFoundry - CloudFoundry Summit Eu...
How dorma+kaba leverages and deploys on CloudFoundry - CloudFoundry Summit Eu...
Adriano Raiano
 
Do you want a SDK with that API? (Nordic APIS April 2014)
Do you want a SDK with that API? (Nordic APIS April 2014)Do you want a SDK with that API? (Nordic APIS April 2014)
Do you want a SDK with that API? (Nordic APIS April 2014)
Nordic APIs
 

Semelhante a Put your client and server to rest - Javaone (20)

Arquitetura chega de mesmice
Arquitetura  chega de mesmiceArquitetura  chega de mesmice
Arquitetura chega de mesmice
 
Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)
Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)
Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)
 
Lost in transaction - Strategies to deal with (in)consistency in distributed ...
Lost in transaction - Strategies to deal with (in)consistency in distributed ...Lost in transaction - Strategies to deal with (in)consistency in distributed ...
Lost in transaction - Strategies to deal with (in)consistency in distributed ...
 
Summit2011 satellites-robinf-20110605
Summit2011 satellites-robinf-20110605Summit2011 satellites-robinf-20110605
Summit2011 satellites-robinf-20110605
 
Satellite Apps around the Cloud: Integrating your infrastructure with JIRA St...
Satellite Apps around the Cloud: Integrating your infrastructure with JIRA St...Satellite Apps around the Cloud: Integrating your infrastructure with JIRA St...
Satellite Apps around the Cloud: Integrating your infrastructure with JIRA St...
 
Mojolicious: what works and what doesn't
Mojolicious: what works and what doesn'tMojolicious: what works and what doesn't
Mojolicious: what works and what doesn't
 
Serverless Days 2019 - Lost in transaction
Serverless Days 2019 - Lost in transactionServerless Days 2019 - Lost in transaction
Serverless Days 2019 - Lost in transaction
 
A reviravolta do desenvolvimento web
A reviravolta do desenvolvimento webA reviravolta do desenvolvimento web
A reviravolta do desenvolvimento web
 
Serverless London 2019 - Coordination of Serverless Functions
Serverless London 2019 - Coordination of Serverless FunctionsServerless London 2019 - Coordination of Serverless Functions
Serverless London 2019 - Coordination of Serverless Functions
 
How dorma+kaba leverages and deploys on CloudFoundry - CloudFoundry Summit Eu...
How dorma+kaba leverages and deploys on CloudFoundry - CloudFoundry Summit Eu...How dorma+kaba leverages and deploys on CloudFoundry - CloudFoundry Summit Eu...
How dorma+kaba leverages and deploys on CloudFoundry - CloudFoundry Summit Eu...
 
CI/CD on Windows-Based Environments - Noam Shochat, eToro - DevOpsDays Tel Av...
CI/CD on Windows-Based Environments - Noam Shochat, eToro - DevOpsDays Tel Av...CI/CD on Windows-Based Environments - Noam Shochat, eToro - DevOpsDays Tel Av...
CI/CD on Windows-Based Environments - Noam Shochat, eToro - DevOpsDays Tel Av...
 
Introducing Spring Cloud Gateway and API Hub for VMware Tanzu
Introducing Spring Cloud Gateway and API Hub for VMware TanzuIntroducing Spring Cloud Gateway and API Hub for VMware Tanzu
Introducing Spring Cloud Gateway and API Hub for VMware Tanzu
 
The Future of Progressive Web Apps - Google for Indonesia
The Future of Progressive Web Apps - Google for IndonesiaThe Future of Progressive Web Apps - Google for Indonesia
The Future of Progressive Web Apps - Google for Indonesia
 
Layar Events in New York and San Francisco
Layar Events in New York and San FranciscoLayar Events in New York and San Francisco
Layar Events in New York and San Francisco
 
Do you want a SDK with that API? (Nordic APIS April 2014)
Do you want a SDK with that API? (Nordic APIS April 2014)Do you want a SDK with that API? (Nordic APIS April 2014)
Do you want a SDK with that API? (Nordic APIS April 2014)
 
Mojolicious. Веб в коробке!
Mojolicious. Веб в коробке!Mojolicious. Веб в коробке!
Mojolicious. Веб в коробке!
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJS
 
The Future of the Web - Cold Front conference 2016
The Future of the Web - Cold Front conference 2016The Future of the Web - Cold Front conference 2016
The Future of the Web - Cold Front conference 2016
 
Passwords suck, but centralized proprietary services are not the answer
Passwords suck, but centralized proprietary services are not the answerPasswords suck, but centralized proprietary services are not the answer
Passwords suck, but centralized proprietary services are not the answer
 
EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services
EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST ServicesEWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services
EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services
 

Último

EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 

Último (20)

ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 

Put your client and server to rest - Javaone

  • 1. Put your client and server to REST with JAX-RS Guilherme Silveira and Jan Algermissen
  • 2.
  • 3. Guilherme Silveira Technical leader, Instructor @guilhermecaelum guilherme.silveira@caelum.com.br
  • 4. Guilherme Silveira Technical leader, Instructor @guilhermecaelum guilherme.silveira@caelum.com.br
  • 5. 2002 guj.com.br 2003 vraptor 2004 caelumobjects.com xp, xstream Guilherme Silveira 2006 scrum Technical leader, Instructor @guilhermecaelum 2009 restfulie, lean guilherme.silveira@caelum.com.br
  • 6.
  • 7. Guilherme Silveira Technical leader, Instructor @guilhermecaelum guilherme.silveira@caelum.com.br
  • 8. Guilherme Silveira Technical leader, Instructor @guilhermecaelum guilherme.silveira@caelum.com.br
  • 9. Training and Consulting Guilherme Silveira Technical leader, Instructor @guilhermecaelum guilherme.silveira@caelum.com.br
  • 10. a ge o Im y -N rr So 2002 Discovered REST 2005 1st pure REST project 2008 REST gaining momentum Jan Algermissen algermissen@acm.org 2009 NORD SC @algermissen
  • 11. bank.com calendar.com travel.com company.com
  • 16. what is the future of integration over the web?
  • 18. Restful Web Services
  • 19. Restful Web create a saas account Services
  • 20. Restful Web create a saas account freeze account Services
  • 21. Restful Web create a saas account freeze account Services reactivate account
  • 22. Web Restful Services
  • 23. Web http Restful Services
  • 24. Web http port 80 Restful Services
  • 25. Web http port 80 firewall heaven Restful Services
  • 27. Web Services xml, json Restful
  • 28. Web Services xml, json Restful get, post, ...
  • 29. Restful Web Services as of 2009 But what about Hypermidia? What about consumers?
  • 30. Restful Web Services as of 2009 But what about Hypermidia? What about consumers? There is much more!
  • 31. unresttrips.com: flight details <?xml version="1.0" encoding="UTF-8" standalum="yes"?> <flight> <information> <from>sao paulo</from> <to>seoul</to> </information>   <value>900.00</value> </flight>
  • 32. service locator when integrating: coupling++ unrest pay unresttrips guilherme
  • 33. service locator when integrating: coupling++ unrest pay unresttrips guilherme
  • 34. resttrips.com: flight details <?xml version="1.0" encoding="UTF-8" standalum="yes"?> <flight> <information> <from>sao paulo</from> <to>seoul</to> </information>   <value>900.00</value> <link rel="payment" href="http://resttrips.com/payment/custom"/ </flight>
  • 35. resttrips.com: flight details <?xml version="1.0" encoding="UTF-8" standalum="yes"?> <flight> <information> <from>sao paulo</from> <to>seoul</to> </information>   <value>900.00</value> <link rel="payment" href="http://resttrips.com/payment/custom"/ </flight>
  • 36. resttrips.com: making the payment flight = Client.at('http://resttrips.com/f/574XR4').get(); confirmation = flight.getLink("payment"). patch(cardInformation, value);
  • 37. resttrips.com: making the payment flight = Client.at('http://resttrips.com/f/574XR4').get(); confirmation = flight.getLink("payment"). patch(cardInformation, value);
  • 38. resttrips.com: changing its payment provider <?xml version="1.0" encoding="UTF-8" standalum="yes"?> <flight> <information> <from>sao paulo</from> <to>seoul</to> </information>   <value>900.00</value> <link rel="payment" href="http://paysite.com/custom"/> </flight>
  • 39. resttrips.com: changing its payment provider <?xml version="1.0" encoding="UTF-8" standalum="yes"?> <flight> <information> <from>sao paulo</from> <to>seoul</to> </information>   <value>900.00</value> <link rel="payment" href="http://paysite.com/custom"/> </flight>
  • 40. dependency injection when integrating: coupling-- restrips pay resttrips.com guilherme paysite.com
  • 41. dependency injection when integrating: coupling-- restrips pay resttrips.com guilherme paysite.com
  • 42. trip = resource http://kayak.com/f/574XR4 payment = resource any_uri_unknown_at_compile_time
  • 43. resttrips.com: sharing a trip flight = Client.at('http://resttrips.com/f/574XR4').get(); confirmation = flight.getLink("payment"). patch(cardInformation, value/2); // send the payment link to another part of the web flight = Client.at('http://resttrips.com/f/574XR4').get(); confirmation = flight.getLink("payment"). patch(cardInformation, value/2);
  • 44. resttrips.com: sharing a trip flight = Client.at('http://resttrips.com/f/574XR4').get(); confirmation = flight.getLink("payment"). patch(cardInformation, value/2); // send the payment link to another part of the web flight = Client.at('http://resttrips.com/f/574XR4').get(); confirmation = flight.getLink("payment"). patch(cardInformation, value/2);
  • 45. resttrips.com: sharing a trip flight = Client.at('http://resttrips.com/f/574XR4').get(); confirmation = flight.getLink("payment"). patch(cardInformation, value/2); // send the payment link to another part of the web flight = Client.at('http://resttrips.com/f/574XR4').get(); confirmation = flight.getLink("payment"). patch(cardInformation, value/2);
  • 46. resttrips.com: sharing a trip flight = Client.at('http://resttrips.com/f/574XR4').get(); confirmation = flight.getLink("payment"). patch(cardInformation, value/2); // send the payment link to another part of the web flight = Client.at('http://resttrips.com/f/574XR4').get(); confirmation = flight.getLink("payment"). patch(cardInformation, value/2);
  • 47. calendar: integrating my systems myself = Client.at('http://users.calendar.com') .with(auth).get(); myself.link("calendar").patch(flight.link("self"));
  • 48. calendar: integrating my systems myself = Client.at('http://users.calendar.com') .with(auth).get(); myself.link("calendar").patch(flight.link("self"));
  • 51. so what? Any update on the flight ==> reflects here Any update on the hotel ==> reflects here Any update on the meeting ==> reflects here
  • 52. so what? r at e! i nt eg us e, ju st o n ’t d Any update on the flight ==> reflects here Any update on the hotel ==> reflects here Any update on the meeting ==> reflects here
  • 53. so what? that was just keeping an URI.
  • 54. so what? that was just keeping an URI. Remove ==> Cancels the flight Remove ==> Cancels the reservation Remove ==> Emails your coworkers
  • 55. so what? that was just keeping an URI. ro l! co nt a li ze en tr no tc do Remove ==> Cancels the flight Remove ==> Cancels the reservation Remove ==> Emails your coworkers
  • 56. integration over the web INTEGRATION is DECENTRALIZING the CONTROL delegating to multiple agents distributed systems
  • 57. does our ‘rest’ sites in 2010 work this way?
  • 58. so what? that was just keeping an URI. Remove ==> Cancels the flight Remove ==> Cancels the reservation Remove ==> Emails your coworkers
  • 59. so what? that was just keeping an URI. a t? fo rm hi ch bu tw Remove ==> Cancels the flight Remove ==> Cancels the reservation Remove ==> Emails your coworkers
  • 61. who is that guy?
  • 62. who is that girl?
  • 63. too easy, right? who is that little girl?
  • 64. too easy, right? who is that little girl? ht er da ug y notm is s he
  • 67. so what? micro formats, media types, rdf etc
  • 68. so what? nk s! er li hyp w ith ats fo rm ic ro m micro formats, media types, rdf etc
  • 70. Put your server to REST leonard richardsons model
  • 71. Server Maturity 1 uri, 1 http verb /services.do?action=install&...
  • 72. Server Maturity 1 uri, 1 http verb /services.do?action=install&... @Path("/services") public class Services {   @GET   public Response services(     @QueryParam("action") String action) {     ServiceFactory factory = new ServiceFactory();     Service service = factory.getServiceFor(action);     return service.execute();   } }
  • 73. Server Maturity 1 uri, 1 http verb public class InstallService {   public Response execute() {     return Response.ok()              .type("application/xml")              .entity("<service>...</service>")              .build();   } }
  • 74. But?
  • 75. 1 uri, 1 http verb /services.do?action=install&... I know them all beforehand.
  • 76. 1 uri, 1 http verb /services.do?action=install&... Any change will break all our clients!
  • 79. a priori knowledge = coupling++
  • 80. Server Maturity Multiple uris, 1 http verb /install?...
  • 81. Server Maturity Multiple uris, 1 http verb /install?... @Path("/services") public class Services {   @GET @Path("install")   public Response install() {     return new InstallService().execute();   }   @GET @Path("uninstall")   public Response uninstall() {     return new UninstallService().execute();   }
  • 83. GET hell GET should not imply in undesireable effects
  • 84. POST hell GET could help us with cache!
  • 85. Server Maturity Multiple uris, multiple verbs POST /cloud GET /cloud/1547437/software POST /cloud/1547437/software
  • 86. rails + restfulie rubyonrails.org
  • 87. rails + restfulie rubyonrails.org class SoftwaresController < ApplicationController      acts_as_restfulie   respond_to :xml, :json      def create     @item = Item.create(params[:item])     respond_with @item, :status => :created   end      def show     @item = Item.find(params[:id])     respond_with @item   end end
  • 89. Vraptor vraptor.org/en @Resource public class SoftwareResource {   public void install() {     Software software = SoftwareRepository.register (software);     response.created(software);   }   public void uninstall() {     response.deleted(software);   } }
  • 90. JAX-RS @Path("/softwares") public class SoftwareResource {   @POST @Consumes("application/xml")   public Response install(Software software) {     software = SoftwareRepository.register(software);     long id = software.getId();     URI uri = UriBuilder.fromPath("/softwares/" + id)                                        .build();     software.install();     return Response.created(uri).build();   }
  • 91. JAX-RS   @DELETE @Path("{id}")   public Response uninstall(@PathParam("id") Long id) {     Software software = SoftwareRepository.retrieve(id);     software.uninstall();     return Response.ok().build();   }
  • 92. Uniform Interface++ Resources++
  • 93. Http verbs example POST creates PUT replaces PATCH updates DELETE removes GET retrieves OPTIONS tells me what i can do ...
  • 94. Is a Restful service a cute CRUD?
  • 95. yes
  • 96. but there is more!
  • 97. hypermedia enter amazon.com
  • 98. hypermedia enter amazon.com search (GET)
  • 99. hypermedia enter amazon.com search (GET) create a payment (POST)
  • 100. hypermedia enter amazon.com search (GET) search (GET) create a payment (POST)
  • 101. hypermedia enter amazon.com search (GET) search (GET) create a basket (POST) create a payment (POST)
  • 102. hypermedia enter amazon.com follow links search (GET) search (GET) create a basket (POST) create a payment (POST)
  • 103. hypermedia enter amazon.com follow links search (GET) search (GET) fill forms create a basket (POST) create a payment (POST)
  • 104. Cloud API GET /user/15 retrieves an user
  • 105. Cloud API GET /user/15 retrieves an user follow GET machines accesses its machines
  • 106. Cloud API GET /user/15 retrieves an user follow GET machines accesses its machines follow POST self installs a new machine
  • 107. Cloud API GET /user/15 retrieves an user follow GET machines accesses its machines follow POST self installs a new machine follow POST payment pay for it
  • 108. retrieves an user $ curl http://localhost:9998/user/574 -i HTTP/1.1 200 OK ...
  • 109. user <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <user>     <link rel="machines" href="/user/574/machines"/>     <name>guilherme silveira</name>     <website>www.caelum.com.br</site>    <link rel="payment" href="/payment/custom"/>     ... </user>
  • 110. user <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <user>     <link rel="machines" href="/user/574/machines"/>     <name>guilherme silveira</name>     <website>www.caelum.com.br</site>    <link rel="payment" href="/payment/custom"/>     ... </user>
  • 111. maschine maschine maschine $ curl http://localhost:9998/user/574/machines -i HTTP/1.1 200 OK Content-Type: application/xml
  • 112. maschine <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <machines xmlns:ns2="http://www.w3.org/2005/Atom">   <machine>     <ns2:link rel="self" href="/user/574/machines/1"/>     <ns2:link rel="software" href="/machines1/softwares"/>     <id>1</id>     <host>www.caelum.com.br</host>     <softwares>       <software>         <id>1234</id>         <ns2:link rel="self" href="/softwares/1234"/>       </software>     </softwares>   </machine> </machines>
  • 113. maschine <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <machines xmlns:ns2="http://www.w3.org/2005/Atom">   <machine>     <ns2:link rel="self" href="/user/574/machines/1"/>     <ns2:link rel="software" href="/machines1/softwares"/>     <id>1</id>     <host>www.caelum.com.br</host>     <softwares>       <software>         <id>1234</id>         <ns2:link rel="self" href="/softwares/1234"/>       </software>     </softwares>   </machine> </machines>
  • 114. payment <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <user>     <link rel="machines" href="/user/574/machines"/>     <name>guilherme silveira</name>     <website>www.caelum.com.br</site>    <link rel="payment" href="/payment/custom"/>     ... </user>
  • 115. payment <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <user>     <link rel="machines" href="/user/574/machines"/>     <name>guilherme silveira</name>     <website>www.caelum.com.br</site>    <link rel="payment" href="/payment/custom"/>     ... </user>
  • 117. @XmlRootElement @XmlType(propOrder= {"id", "host", "softwares", "links"}) public class Machine {   private final all variables here;   @XmlElement(name="link", namespace="http://www.w3.org/2005/Atom")   public List<Link> getLinks() {     return Arrays.asList(       Link.to("/machines/" + getId(), "self"),       Link.to("/machines/" + getId() + "/softwares", "softwares")     );   }   @XmlElementWrapper(name="softwares")   @XmlElement(name="software")   public List<Software> getSoftwares() {     return softwares;   }   public void install(Software software) {     getSoftwares().add(software);   }   public void uninstall(Software software) {     getSoftwares().remove(software);   } } Machine.java
  • 118. @XmlRootElement @XmlType(propOrder= {"id", "host", "softwares", "links"}) public class Machine {   private final all variables here;   @XmlElement(name="link", namespace="http://www.w3.org/2005/Atom")   public List<Link> getLinks() {     return Arrays.asList(       Link.to("/machines/" + getId(), "self"),       Link.to("/machines/" + getId() + "/softwares", "softwares")     );   }   @XmlElementWrapper(name="softwares")   @XmlElement(name="software")   public List<Software> getSoftwares() {     return softwares;   }   public void install(Software software) {     getSoftwares().add(software);   }   public void uninstall(Software software) {     getSoftwares().remove(software);   } } Machine.java
  • 119. @Path("/machines") public class MachineResource { MachineResource @Path("{id}/softwares") public SoftwareResource softwares(@PathParam("id") Long id) { Machine machine = new MachineRepository().retrieve(id); if (machine != null) { SoftwareResource softwareResource = new SoftwareResource(); softwareResource.setMachine(machine); return softwareResource; } throw new WebApplicationException(404); } @POST @Consumes("application/xml") public Response create(Machine machine) { Long id = new MachineRepository().save(machine); return Response.created(UriBuilder.fromPath("/" + id).build()).build(); } @GET @Path("{id}") @Produces("application/xml") public Machine show(@PathParam("id") Long id) { return new MachineRepository().retrieve(id); } @GET @Produces("application/xml") public Machines list() { Machines machines = new Machines(); machines.setMachine(new MachineRepository().list()); return machines;
  • 120. @Path("/machines") public class MachineResource { MachineResource @Path("{id}/softwares") public SoftwareResource softwares(@PathParam("id") Long id) { Machine machine = new MachineRepository().retrieve(id); if (machine != null) { SoftwareResource softwareResource = new SoftwareResource(); softwareResource.setMachine(machine); return softwareResource; } throw new WebApplicationException(404); } @POST @Consumes("application/xml") public Response create(Machine machine) { Long id = new MachineRepository().save(machine); return Response.created(UriBuilder.fromPath("/" + id).build()).build(); } @GET @Path("{id}") @Produces("application/xml") public Machine show(@PathParam("id") Long id) { return new MachineRepository().retrieve(id); } @GET @Produces("application/xml") public Machines list() { Machines machines = new Machines(); machines.setMachine(new MachineRepository().list()); return machines;
  • 121. Server Model according to Leonard Richardson, 2008 one uri + one verb
  • 122. Server Model according to Leonard Richardson, 2008 Ugly one uri + one verb
  • 123. Server Model according to Leonard Richardson, 2008 multiple uris one uri + one verb
  • 124. Server Model according to Leonard Richardson, 2008 Less ugly multiple uris one uri + one verb
  • 125. Server Model according to Leonard Richardson, 2008 multiple verbs multiple uris one uri + one verb
  • 126. Server Model according to Leonard Richardson, 2008 cute CRUD multiple verbs multiple uris one uri + one verb
  • 127. Server Model rest according to Leonard Richardson, 2008 hypermedia multiple verbs multiple uris one uri + one verb
  • 128. JAX-RS wishlist VRaptor and Restfulie
  • 130. 1. conventions? @Path("/services") public class Services {   @GET   public Response services(     @QueryParam("action") String action) {     ServiceFactory factory = new ServiceFactory();     Service service = factory.getServiceFor(action);     return service.execute();   } }
  • 131. Convention over Configuration @Resource public class Services { private final ServiceFactory factory; public Services(ServiceFactory factory) { this.factory = factory; } public void services(String action) { factory.getServiceFor(action).execute(); } }
  • 132. do you want to avoid copy+paste?
  • 133. yes!
  • 134. yes!
  • 135. 2. TDD: hard to test @Path("/products") public class Products { coupled to the   @GET implementation   public Response create(     @QueryParam("what") String what) {     // persists     return Response.ok()              .type("application/xml")              .entity("<product>...</product>")              .build();   } }
  • 136. TDD: mock it coupled to the interface couple-- @Resource public class Services { private final Response response; public Services(Response response) { this.response = response; } public void services(String action) { response.getServiceFor(action).execute(); } }
  • 137. TDD: mock it coupled to the interface couple-- @Resource public class Services { private final Response response; public Services(Response response) { this.response = response; } public void services(String action) { response.getServiceFor(action).execute(); } }
  • 138. 3. Content negotiation by hand @Path("/softwares") public class SoftwareResource {   @POST @Consumes("application/xml")   public Response install(Software software) {     software = SoftwareRepository.register(software);     long id = software.getId();     URI uri = UriBuilder.fromPath("/softwares/" + id)                                        .build(); software.install();     return Response.created(uri).build();   }
  • 139. Let us do it for you. @Resource public class SoftwareResource { @Post @Consumes   public void install(Software software) {     software = SoftwareRepository.register(software);     response.created(software);   } }
  • 140. Let us do it for you. @Resource public class SoftwareResource { @Post @Consumes   public void install(Software software) {     software = SoftwareRepository.register(software);     response.created(software);   } }
  • 141. 4. URI coupling writing the URI once ...   @GET @Path("/softwares/{id}")   public Response install(@QueryParam("id") Software software) { // ...   }
  • 142. 4. URI coupling writing the URI again several times @Path("/softwares") public class SoftwareResource {   @POST @Consumes("application/xml")   public Response install(Software software) {     software = SoftwareRepository.register(software);     long id = software.getId();     URI uri = UriBuilder.fromPath("/softwares/" + id)                                        .build(); software.install();     return Response.created(uri).build();   }
  • 143. 4. URI coupling code @Path("/softwares") public class SoftwareResource {   @POST @Consumes("application/xml")   public Response install(Software software) {     software = SoftwareRepository.register(software);     long id = software.getId();     URI uri = UriBuilder.fromPath("/softwares/" + id)                                        .build(); software.install();     return Response.created(uri).build();   }
  • 144. ZERO uri replication @Resource public class SoftwareResource { @Post @Consumes   public void install(Software software) {     // ...     response.use(SoftwareResource.class).show(software);   } }
  • 145. ZERO uri replication @Resource public class SoftwareResource { @Post @Consumes   public void install(Software software) {     // ...     response.use(SoftwareResource.class).show(software);   } }
  • 146. 5. Parameter list @Path("/machines") public class MachineResource { @Path("{id}/softwares") public SoftwareResource softwares(@PathParam("id") Long id) { Machine machine = new MachineRepository().retrieve(id); if (machine == null) { throw new WebApplicationException(404); } // ... } }
  • 147. Yes, we can do it. @Resource public class MachineResource { @Post ("{m.id}/softwares") public SoftwareResource softwares(Machine m) { Machine machine = new MachineRepository().retrieve(m // ... } } parameter converter chain of responsability
  • 148. Yes, we can do it. @Resource public class MachineResource { @Post ("{m.id}/softwares") public SoftwareResource softwares(Machine m) { Machine machine = new MachineRepository().retrieve(m // ... } } parameter converter chain of responsability
  • 150. Response response = client.at ("http://localhost:9998/user/574").get(); 6. Client internal DSLs
  • 151. Response response = client.at ("http://localhost:9998/user/574").get(); User user = response.getResource(); System.out.println("user: " + user.getName()); 6. Client internal DSLs
  • 152. User user = response.getResource(); System.out.println("user: " + user.getName()); Link link = resource(user).getLink("machine"); response = link.follow().post(new Machine());
  • 153. Link link = resource(user).getLink("machine"); response = link.follow().post(new Machine()); double amount = resource(user).refresh(). getAmountDue();
  • 154. double amount = resource(user).refresh(). getAmountDue(); link = resource(user).getLink("payment"); Payment payment = new Payment(amount); response = link.follow().post(payment);
  • 155. link = resource(user).getLink("payment"); Payment payment = new Payment(amount); response = link.follow().post(payment); System.out.println("payment completed");
  • 156. link = resource(user).getLink("payment"); Payment payment = new Payment(amount); response = link.follow().post(payment); System.out.println("payment completed"); i was looking for a DSL and i did not know it!
  • 158. “Jersey View Client” • Developed early 2010 • w/ Paul Sandoz (@paulsandoz) • To-be Jersey RESTful client API • Feedback welcome!
  • 159. Goals • Encourage RESTful client side programming • Natural coding model • Resemble JAX-RS annotation style
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 168. Web Browser Tasks • GET resource after user enters URL
  • 169. Web Browser Tasks • GET resource after user enters URL • Build up Web page
  • 170. Web Browser Tasks • GET resource after user enters URL • Build up Web page • Show informatin (title, content)
  • 171. Web Browser Tasks • GET resource after user enters URL • Build up Web page • Show informatin (title, content) • Expose links and forms
  • 172. Web Browser Tasks • GET resource after user enters URL • Build up Web page • Show informatin (title, content) • Expose links and forms • Act upon link activation or form submission
  • 174. A Web Page • Has a location
  • 175. A Web Page • Has a location • Build from response(s)
  • 176. A Web Page • Has a location • Build from response(s) • Holds application state
  • 177. A Web Page • Has a location • Build from response(s) • Holds application state • Exposes application state
  • 178. A Web Page • Has a location • Build from response(s) • Holds application state • Exposes application state • Exposes links and forms
  • 179. A Web Page • Has a location • Build from response(s) • Holds application state • Exposes application state • Exposes links and forms • Assumptions
  • 182. User Agent • Use entry URI to start application
  • 183. User Agent • Use entry URI to start application • Build up application state from response(s)
  • 184. User Agent • Use entry URI to start application • Build up application state from response(s) • Make state available
  • 185. User Agent • Use entry URI to start application • Build up application state from response(s) • Make state available • Make hypermedia controls activatable
  • 186. User Agent • Use entry URI to start application • Build up application state from response(s) • Make state available • Make hypermedia controls activatable • Construct request upon control activation
  • 187. A View
  • 188. A View • Bound to resource
  • 189. A View • Bound to resource • Build from response(s)
  • 190. A View • Bound to resource • Build from response(s) • Holds application state
  • 191. A View • Bound to resource • Build from response(s) • Holds application state • Exposes application state
  • 192. A View • Bound to resource • Build from response(s) • Holds application state • Exposes application state • Enables activation of controls
  • 193. A View • Bound to resource • Build from response(s) • Holds application state • Exposes application state • Enables activation of controls • Bundles Assumptions
  • 194. View: Combination of state and assumptions, bound to a URI
  • 195. So where is the difference?
  • 198. Can’t do machine REST with a single kind of view
  • 199. Not just one kind of application state
  • 200. Atom Pub • Service view • Feed view • Entry View
  • 201. Our Example • User account view • Machine View • Invoice View
  • 202. Client Side API?
  • 203. Use classes to represent kinds of views
  • 204. A view class for a Web Page View WebPageView pageView = client.view( “https://twitter.com/signup”,WebPageView.class); Form form = page.getFormsByIndex(0); form.name = “John”; form.submit();
  • 206. View Classes • Relate instance to resource
  • 207. View Classes • Relate instance to resource • Handle response
  • 208. View Classes • Relate instance to resource • Handle response • Build up application state
  • 209. View Classes • Relate instance to resource • Handle response • Build up application state • Expose application state
  • 210. View Classes • Relate instance to resource • Handle response • Build up application state • Expose application state • Expose hypermedia controls
  • 211. View Classes • Relate instance to resource • Handle response • Build up application state • Expose application state • Expose hypermedia controls • Perform requests upon control activation
  • 212. View Classes • Relate instance to resource • Handle response • Build up application state • Expose application state • Expose hypermedia controls • Perform requests upon control activation • Bundle assumptions
  • 213. A class for account views URI ACCOUNT_URI = new URI( “http://example.org/saas/user/john/account”); Client client = new Client(); // Create view instance bound to a URI AccountView av = client.view(ACCOUNT_URI, AccountView.class); // Access application state held by view // Invoke controls exposed by view
  • 214. A Media Type GET /saas/user/john/account 200 Ok Content-Type: application/saas <account> <machines href=”./machines” accept=”application/saas;type=machine”/> <payments href=”./payments” accept=”application/saas;type=payment”/> <userData> <name>John Doe</name> ... </userData> </account>
  • 215. public class AccountView { // hold state private ViewResource machineCollection; private ViewResource paymentProcessor; private String userName; @GET @Consumes(“application/saas;type=account”) public void build(Account account) { // build state from response } public String getUserName() { return userName; } // <machines href=””/> control exposed public CreatedMachineView addMachine(Machine machine) { return machineCollection.post(machine, CreatedMachineView.class) } // <payments href=””/> control exposed public void submitPayment(Payment payment) { paymentProcessor.post(payment); } }
  • 216. public class AccountView { // hold state private ViewResource machineCollection; private ViewResource paymentProcessor; private String userName; @GET @Consumes(“application/saas;type=account”) public void build(Account account) { // build state from response } public String getUserName() { return userName; } // <machines href=””/> control exposed public CreatedMachineView addMachine(Machine machine) { return machineCollection.post(machine, CreatedMachineView.class) } // <payments href=””/> control exposed public void submitPayment(Payment payment) { paymentProcessor.post(payment); } }
  • 217. public class AccountView { // hold state private ViewResource machineCollection; private ViewResource paymentProcessor; private String userName; @GET @Consumes(“application/saas;type=account”) public void build(Account account) { // build state from response } public String getUserName() { return userName; } // <machines href=””/> control exposed public CreatedMachineView addMachine(Machine machine) { return machineCollection.post(machine, CreatedMachineView.class) } // <payments href=””/> control exposed public void submitPayment(Payment payment) { paymentProcessor.post(payment); } }
  • 218. public class AccountView { // hold state private ViewResource machineCollection; private ViewResource paymentProcessor; private String userName; @GET @Consumes(“application/saas;type=account”) public void build(Account account) { // build state from response } public String getUserName() { return userName; } // <machines href=””/> control exposed public CreatedMachineView addMachine(Machine machine) { return machineCollection.post(machine, CreatedMachineView.class) } // <payments href=””/> control exposed public void submitPayment(Payment payment) { paymentProcessor.post(payment); } }
  • 219. public class AccountView { // hold state private ViewResource machineCollection; private ViewResource paymentProcessor; private String userName; @GET @Consumes(“application/saas;type=account”) public void build(Account account) { // build state from response } public String getUserName() { return userName; } // <machines href=””/> control exposed public CreatedMachineView addMachine(Machine machine) { return machineCollection.post(machine, CreatedMachineView.class) } // <payments href=””/> control exposed public void submitPayment(Payment payment) { paymentProcessor.post(payment); } }
  • 220. public class AccountView { // hold state private ViewResource machineCollection; private ViewResource paymentProcessor; private String userName; @GET @Consumes(“application/saas;type=account”) public void build(Account account) { // build state from response } public String getUserName() { return userName; } // <machines href=””/> control exposed public CreatedMachineView addMachine(Machine machine) { return machineCollection.post(machine, CreatedMachineView.class) } // <payments href=””/> control exposed public void submitPayment(Payment payment) { paymentProcessor.post(payment); } }
  • 221. Choosing a certain view class to handle a response manifests an assumption!
  • 222. Using View Classes AccountView accountView = client.view( ACCOUNT_URI,AccountView.class); LOG.info(“Working on account for “ + accountView.getUserName()); Machine machine = newMachine(); CreatedMachineView cmv = accountView.addMachine(machine); LOG.info("New machine is at: " + cmv.getLocation()); InvoiceView invoiceView = cmv.getInvoiceView(); Payment payment = new Payment(invoiceView.getAmount(), myCreditCardData); accountView.makePayment(payment);
  • 223. Using View Classes AccountView accountView = client.view( ACCOUNT_URI,AccountView.class); LOG.info(“Working on account for “ + accountView.getUserName()); Machine machine = newMachine(); CreatedMachineView cmv = accountView.addMachine(machine); LOG.info("New machine is at: " + cmv.getLocation()); InvoiceView invoiceView = cmv.getInvoiceView(); Payment payment = new Payment(invoiceView.getAmount(), myCreditCardData); accountView.makePayment(payment);
  • 224. Using View Classes AccountView accountView = client.view( ACCOUNT_URI,AccountView.class); LOG.info(“Working on account for “ + accountView.getUserName()); Machine machine = newMachine(); CreatedMachineView cmv = accountView.addMachine(machine); LOG.info("New machine is at: " + cmv.getLocation()); InvoiceView invoiceView = cmv.getInvoiceView(); Payment payment = new Payment(invoiceView.getAmount(), myCreditCardData); accountView.makePayment(payment);
  • 225. Using View Classes AccountView accountView = client.view( ACCOUNT_URI,AccountView.class); LOG.info(“Working on account for “ + accountView.getUserName()); Machine machine = newMachine(); CreatedMachineView cmv = accountView.addMachine(machine); LOG.info("New machine is at: " + cmv.getLocation()); InvoiceView invoiceView = cmv.getInvoiceView(); Payment payment = new Payment(invoiceView.getAmount(), myCreditCardData); accountView.makePayment(payment);
  • 226. Using View Classes AccountView accountView = client.view( ACCOUNT_URI,AccountView.class); LOG.info(“Working on account for “ + accountView.getUserName()); Machine machine = newMachine(); CreatedMachineView cmv = accountView.addMachine(machine); LOG.info("New machine is at: " + cmv.getLocation()); InvoiceView invoiceView = cmv.getInvoiceView(); Payment payment = new Payment(invoiceView.getAmount(), myCreditCardData); accountView.makePayment(payment);
  • 227. Using View Classes AccountView accountView = client.view( ACCOUNT_URI,AccountView.class); LOG.info(“Working on account for “ + accountView.getUserName()); Machine machine = newMachine(); CreatedMachineView cmv = accountView.addMachine(machine); LOG.info("New machine is at: " + cmv.getLocation()); InvoiceView invoiceView = cmv.getInvoiceView(); Payment payment = new Payment(invoiceView.getAmount(), myCreditCardData); accountView.makePayment(payment);
  • 228. Using View Classes AccountView accountView = client.view( ACCOUNT_URI,AccountView.class); LOG.info(“Working on account for “ + accountView.getUserName()); Machine machine = newMachine(); CreatedMachineView cmv = accountView.addMachine(machine); LOG.info("New machine is at: " + cmv.getLocation()); InvoiceView invoiceView = cmv.getInvoiceView(); Payment payment = new Payment(invoiceView.getAmount(), myCreditCardData); accountView.makePayment(payment);
  • 229. Using View Classes AccountView accountView = client.view( ACCOUNT_URI,AccountView.class); LOG.info(“Working on account for “ + accountView.getUserName()); Machine machine = newMachine(); CreatedMachineView cmv = accountView.addMachine(machine); LOG.info("New machine is at: " + cmv.getLocation()); InvoiceView invoiceView = cmv.getInvoiceView(); Payment payment = new Payment(invoiceView.getAmount(), myCreditCardData); accountView.makePayment(payment);
  • 231. Things to Note • Think of view like of browser window
  • 232. Things to Note • Think of view like of browser window • Can keep them around, go back, use any time
  • 233. Things to Note • Think of view like of browser window • Can keep them around, go back, use any time • Handle for application state
  • 234. Things to Note • Think of view like of browser window • Can keep them around, go back, use any time • Handle for application state • View class is single point of code
  • 235. Things to Note • Think of view like of browser window • Can keep them around, go back, use any time • Handle for application state • View class is single point of code • Bundles code and expectations
  • 236. Things to Note • Think of view like of browser window • Can keep them around, go back, use any time • Handle for application state • View class is single point of code • Bundles code and expectations • Views classes used define application
  • 239. After-Talk Discussion Come and discuss RESTfulie and Jersey View Client.
  • 241. In a world with serious issues
  • 242. In a world with serious issues
  • 243. In a world with serious issues
  • 244. In a world with serious issues
  • 245. What is the magical solution?
  • 246. sunday in the park “Ah, yes, a similar thing happens all the time when flaying frisbee in the park with my dog. When I throw the frisbee and the dog tries to catch it in his teeth, everyone seems to be happy.”
  • 247. sunday in the park “However, when the dog tries to throw the frisbee and I try to catch it in my teeth, it just doesn't seem to work well for either of us.” Roy Fielding, REST creator
  • 248. If JMS does not fit your problem, do not try to fit your solution within JMS.
  • 249. If SOA does not fit your problem, do not try to fit your solution within SOA.
  • 250. If REST does not fit your problem, do not try to fit your solution within REST.
  • 252. The golden rule If * does not fit your problem, do not try to fit your solution within *.
  • 253. code samples Lucas Cavalcanti (java server) @lucascs Anderson Leite (ruby) @anderson_leite
  • 256. Further reading Roy Fielding dissertation Rest in Practice, Jim Webber and others
  • 257. Further reading Roy Fielding dissertation Rest in Practice, Jim Webber and others Restful Webservices Cookbook, Subbu Allamaraju
  • 258. Further reading Roy Fielding dissertation Rest in Practice, Jim Webber and others Restful Webservices Cookbook, Subbu Allamaraju Restful Web Services, Richardson and Ruby
  • 259. Further reading Roy Fielding dissertation Rest in Practice, Jim Webber and others Restful Webservices Cookbook, Subbu Allamaraju Restful Web Services, Richardson and Ruby JAX-RS specification
  • 260. Further reading Roy Fielding dissertation Rest in Practice, Jim Webber and others Restful Webservices Cookbook, Subbu Allamaraju Restful Web Services, Richardson and Ruby JAX-RS specification Infoq articles on REST
  • 261. Further reading Roy Fielding dissertation Rest in Practice, Jim Webber and others Restful Webservices Cookbook, Subbu Allamaraju Restful Web Services, Richardson and Ruby JAX-RS specification Infoq articles on REST Restfulie guide
  • 264. Jersey related Jersey related posts http://www.nordsc.com/blog/?cat=28
  • 265. Jersey related Jersey related posts http://www.nordsc.com/blog/?cat=28 Repository
  • 266. Jersey related Jersey related posts http://www.nordsc.com/blog/?cat=28 Repository https://jersey.dev.java.net/
  • 267. Jersey related Jersey related posts http://www.nordsc.com/blog/?cat=28 Repository https://jersey.dev.java.net/ Presentation
  • 268. Jersey related Jersey related posts http://www.nordsc.com/blog/?cat=28 Repository https://jersey.dev.java.net/ Presentation http://www.nordsc.com/presentations/j1/
  • 270. Interviews and Presentations Stefan Tilkov interview on InfoQ
  • 271. Interviews and Presentations Stefan Tilkov interview on InfoQ http://bit.ly/9RUXKL
  • 272. Interviews and Presentations Stefan Tilkov interview on InfoQ http://bit.ly/9RUXKL Leonard Richardson’s presentation at QCon
  • 273. Interviews and Presentations Stefan Tilkov interview on InfoQ http://bit.ly/9RUXKL Leonard Richardson’s presentation at QCon http://bit.ly/dj2W66
  • 274. Interviews and Presentations Stefan Tilkov interview on InfoQ http://bit.ly/9RUXKL Leonard Richardson’s presentation at QCon http://bit.ly/dj2W66 Martin Fowler on REST
  • 275. Interviews and Presentations Stefan Tilkov interview on InfoQ http://bit.ly/9RUXKL Leonard Richardson’s presentation at QCon http://bit.ly/dj2W66 Martin Fowler on REST http://bit.ly/bx61ci
  • 277. Interviews and Presentations Ian Robinson and Jim Webber interview
  • 278. Interviews and Presentations Ian Robinson and Jim Webber interview http://bit.ly/aEuzj3
  • 279. Interviews and Presentations Ian Robinson and Jim Webber interview http://bit.ly/aEuzj3 Jan Algermissen classification
  • 280. Interviews and Presentations Ian Robinson and Jim Webber interview http://bit.ly/aEuzj3 Jan Algermissen classification http://bit.ly/cycFBF
  • 281. Interviews and Presentations Ian Robinson and Jim Webber interview http://bit.ly/aEuzj3 Jan Algermissen classification http://bit.ly/cycFBF Guilherme Silveira on REST clients
  • 282. Interviews and Presentations Ian Robinson and Jim Webber interview http://bit.ly/aEuzj3 Jan Algermissen classification http://bit.ly/cycFBF Guilherme Silveira on REST clients http://bit.ly/aHCglv
  • 286. code samples JAX-RS http://jcp.org/en/jsr/detail?id=311 Rails
  • 287. code samples JAX-RS http://jcp.org/en/jsr/detail?id=311 Rails http://rubyonrails.org
  • 288. code samples JAX-RS http://jcp.org/en/jsr/detail?id=311 Rails http://rubyonrails.org Restfulie
  • 289. code samples JAX-RS http://jcp.org/en/jsr/detail?id=311 Rails http://rubyonrails.org Restfulie http://restfulie.caelumobjects.com
  • 290. code samples JAX-RS http://jcp.org/en/jsr/detail?id=311 Rails http://rubyonrails.org Restfulie http://restfulie.caelumobjects.com VRaptor
  • 291. code samples JAX-RS http://jcp.org/en/jsr/detail?id=311 Rails http://rubyonrails.org Restfulie http://restfulie.caelumobjects.com VRaptor http://vraptor.org/en

Notas do Editor

  1. Hello Everybody! First, thank you for being here. I am aware that there is a parallel talk on JAX-RS also given by Paul Sandoz. So we are glad you made it to us. I am Jan Algermissen. I am working as a software architecture consultant, with an emphasis on REST. of course. I am running a small company called NORD, based in Germany. We are aiming at taking that extra step to really see REST being adopted in the enterprise. To really make a difference there. I have found that there are a several aspects of REST that are still a little vague. That is a major obstacle towards applying REST in an enterprise environment. One of those areas is definitely the client side programming model. And that&amp;#x2019;s why I am here to inform about some additions Paul Sandoz and I have been making to the Jersey-Client project.
  2. 1 uri. 1 http verb
  3. implementing a specific response
  4. Project name: Jersey-View-Client Build with Paul Sandoz early 2010 Has been around for a while, but not really been noticed. Trying to change that ... welcome your feedback.
  5. Main goals: 1. Encourage RESTful design 2. Intuitive coding model 3. Use the JAX-RS annotation-based style as much as possible Question is: How do we go about doing that? Use what we know and start from looking at an HTML user agent
  6. Look at what we know and work our way up from there.
  7. What is happening here?
  8. What is happening here?
  9. What is happening here?
  10. What is happening here?
  11. What is happening here?
  12. Think in terms of &amp;#x201C;browser window&amp;#x201D; Assumptions about the referenced resources
  13. Think in terms of &amp;#x201C;browser window&amp;#x201D; Assumptions about the referenced resources
  14. Think in terms of &amp;#x201C;browser window&amp;#x201D; Assumptions about the referenced resources
  15. Think in terms of &amp;#x201C;browser window&amp;#x201D; Assumptions about the referenced resources
  16. Think in terms of &amp;#x201C;browser window&amp;#x201D; Assumptions about the referenced resources
  17. Think in terms of &amp;#x201C;browser window&amp;#x201D; Assumptions about the referenced resources
  18. User Agents generally need to do 4 things
  19. User Agents generally need to do 4 things
  20. User Agents generally need to do 4 things
  21. User Agents generally need to do 4 things
  22. User Agents generally need to do 4 things
  23. Where is the difference between Browser and the generic case?
  24. Browsers are based on the notion of a single kind of view.
  25. Cannot build many useful machine driven applications with a single kind of view.
  26. Image, Example
  27. What is our client side API going to look like? How can we naturally support different kinds of views?
  28. What are the ingredients of view classes?
  29. What are the ingredients of view classes?
  30. What are the ingredients of view classes?
  31. What are the ingredients of view classes?
  32. What are the ingredients of view classes?
  33. What are the ingredients of view classes?
  34. What are the ingredients of view classes?
  35. Need to build this exmple up slowly steps, no other examples.
  36. This can be compared with an Atom service document. Tells the client what resources are available for which purpose.
  37. Need to build this exmple up slowly steps, no other examples.
  38. Need to build this exmple up slowly steps, no other examples.
  39. Need to build this exmple up slowly steps, no other examples.
  40. Need to build this exmple up slowly steps, no other examples.
  41. Need to build this exmple up slowly steps, no other examples.
  42. This is important because here you see that the AccountView makes certain assumptions how the response is going to be processable. In Browser-land we do not have that problem because there is only one kind of view!!!
  43. Can keep around - like we keep a search result open and go to the hits in new tabs Handle for application state - keep around, save, log, send to support team View class as single point of code - Response-, state-, controls handling and expectation nicely bundled - Single point of documentation
  44. Can keep around - like we keep a search result open and go to the hits in new tabs Handle for application state - keep around, save, log, send to support team View class as single point of code - Response-, state-, controls handling and expectation nicely bundled - Single point of documentation
  45. Can keep around - like we keep a search result open and go to the hits in new tabs Handle for application state - keep around, save, log, send to support team View class as single point of code - Response-, state-, controls handling and expectation nicely bundled - Single point of documentation
  46. Can keep around - like we keep a search result open and go to the hits in new tabs Handle for application state - keep around, save, log, send to support team View class as single point of code - Response-, state-, controls handling and expectation nicely bundled - Single point of documentation
  47. Can keep around - like we keep a search result open and go to the hits in new tabs Handle for application state - keep around, save, log, send to support team View class as single point of code - Response-, state-, controls handling and expectation nicely bundled - Single point of documentation
  48. Can keep around - like we keep a search result open and go to the hits in new tabs Handle for application state - keep around, save, log, send to support team View class as single point of code - Response-, state-, controls handling and expectation nicely bundled - Single point of documentation
  49. Can keep around - like we keep a search result open and go to the hits in new tabs Handle for application state - keep around, save, log, send to support team View class as single point of code - Response-, state-, controls handling and expectation nicely bundled - Single point of documentation