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
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
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
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
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();
}
}
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();
}
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();
}
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
...
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;
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();
}
}
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
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);
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!
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
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
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
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
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();
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);
}
}
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
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.
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
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
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&#x2019;s why I am here to inform about some additions Paul Sandoz and I have been making to the Jersey-Client project.
1 uri. 1 http verb
implementing a specific response
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.
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
Look at what we know and work our way up from there.
What is happening here?
What is happening here?
What is happening here?
What is happening here?
What is happening here?
Think in terms of &#x201C;browser window&#x201D;
Assumptions about the referenced resources
Think in terms of &#x201C;browser window&#x201D;
Assumptions about the referenced resources
Think in terms of &#x201C;browser window&#x201D;
Assumptions about the referenced resources
Think in terms of &#x201C;browser window&#x201D;
Assumptions about the referenced resources
Think in terms of &#x201C;browser window&#x201D;
Assumptions about the referenced resources
Think in terms of &#x201C;browser window&#x201D;
Assumptions about the referenced resources
User Agents generally need to do 4 things
User Agents generally need to do 4 things
User Agents generally need to do 4 things
User Agents generally need to do 4 things
User Agents generally need to do 4 things
Where is the difference between Browser and the generic case?
Browsers are based on the notion of a single kind of view.
Cannot build many useful machine driven applications with a single kind of view.
Image, Example
What is our client side API going to look like?
How can we naturally support different kinds of views?
What are the ingredients of view classes?
What are the ingredients of view classes?
What are the ingredients of view classes?
What are the ingredients of view classes?
What are the ingredients of view classes?
What are the ingredients of view classes?
What are the ingredients of view classes?
Need to build this exmple up slowly steps, no other examples.
This can be compared with an Atom service document.
Tells the client what resources are available for which purpose.
Need to build this exmple up slowly steps, no other examples.
Need to build this exmple up slowly steps, no other examples.
Need to build this exmple up slowly steps, no other examples.
Need to build this exmple up slowly steps, no other examples.
Need to build this exmple up slowly steps, no other examples.
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!!!
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
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
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
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
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
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
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