HTTP ALL THE THINGS
Simplifying Rich Applications by
Respecting the Rules of the Web
Me
Nate Abele
Former lead developer, CakePHP
Founder & current lead developer, Lithium
Member, AngularUI
@nateabele
History
1998: SOAP & XMLRPC
SOAP
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header></soap:Header>
<soap:Body>
<m:SomeCommand xmlns:m="...">
<m:BodyOfMessage>...</m:BodyOfMessage>
</m:SomeCommand>
</soap:Body>
</soap:Envelope>
Or...
XML-RPC
<?xml version="1.0"?>
<methodCall>
<methodName>examples.getStateName</methodName>
<params>
<param>
<value><i4>40</i4></value>
</param>
</params>
</methodCall>
:-(
POST *
Invocaction details in body
Format lock-in
No relationships
No discoverability
2000: REST
REST Constraints
Client-Server
Stateless
Cacheable
Uniform Interface
Opaque Layering
Code-on-Demand
The 4 Levels
RPC over HTTP (i.e. SOAP)
Resources
Verbs
Hypermedia Controls
Now: Hypermedia /
HATEOAS
¿Hypermedia?
Content negotiation
State traversal
Content negotiation
application/json ...?
Content negotiation
application/json
FALE
Content negotiation
Better:
application/rss+xml
Content negotiation
application/vnd.twitter.stream+json
// I can decode this!
json_decode()

/**
* I can understand this
!
*/
class Tweet {
protected $username;
protected $text;
// ...
}
State traversal
Client: “What's next?”
We already do this!
Browsers
<link rel="stylesheet" href="/css/app.css" />
<link rel="next" href="/next" />
<link
rel="alternate"
type="application/rss+xml"
href="/posts.rss"
/>
Users

(with the help of browsers)
<a href="/next" />Next</a>
<form></form>
Atom?
<link
rel="foo"
type="text/foo"
href="http://foo"
/>
JSON!
[{
title: "Finish the demo",
completed: false,
$links: {
self: { href: "http://my.app/tasks/1138" },
owner: { href: "http://my.app/users/nate" },
subtasks: { href: "http://my.app/tasks/1138/subtasks"}
}
}]
Why?
AngularJS
Valid alternatives
EmberJS
KnockoutJS
Backbone (kind of, not really)
AngularJS
Higher level of abstraction
Simple, well-designed architecture
Ridiculously simple unit testing
Event binding
Event binding
jQuery

<input type="text" id="name" />
<h1>Hello!</h1>
<script type="text/javascript">
$(document).ready(function() {
$('#name').keydown(function(e) {
$('h1').html("Hello " + e.target.value + "!")
});
});
</script>
Event binding
AngularJS

<input type="text" ng-model="name" />
<h1>Hello {{ name }}!</h1>

Hello !
Iteration
jQuery

<ul class="greetings"></ul>
<script type="text/javascript">
$(["Hello", "Hola", "Ciao"]).each(function(k, v) {
$(".greeting").append("<li>" + v + " World</li>"
});
</script>
Iteration
AngularJS

<ul>
<li ng-repeat="greet in ['Hello', 'Hola', 'Ciao']">
{{ greet }} World
</li>
</ul>

Hello World
Hola World
Ciao World
<ul>
<li ng-repeat="greet in ['Hello', 'Hola', 'Ciao']">
{{ greet }} World
</li>
</ul>

Hello World
Hola World
Ciao World
Organization
AngularJS

Item:

Qty: 0

Price: 0

Total: $0.00

Total: $0.00
Organization
AngularJS

<div ng-controller="CheckoutController">
<div ng-repeat="item in items">
Item: <input type="text" ng-model="item.name">
Qty: <input type="number" ng-model="item.qty">
Price: <input type="number" ng-model="item.price">
Total: <div class="total">
{{ item.qty * item.price | currency: "$" }}
</div>
</div>
<hr>
<div>Total: {{ total() | currency: "$" }}</div>
</div>
Organization
AngularJS

function CheckoutController($scope) {
$scope.items = $scope.items || [{ price: 0, qty: 0 }];
$scope.total = function() {
if ($scope.items[$scope.items.length - 1].qty) {
$scope.items.push({ price: 0, qty: 0 });
}
return $scope.items.map(function(item) {
return item.qty * item.price;
}).reduce(function(a, b) {
return a + b;
});
};
}
Organization
jQuery

¿Ummm...?
Organization
jQuery
*shrug*
Testability
AngularJS

describe("Shopping cart", function() {
describe("Checkout widget", function() {
it("should create a default element", function() {
var scope = {},
controller = new CheckoutController(scope);
expect(scope.items.length).toBe(1);
expect(scope.items[0].qty).toBe(0);
expect(scope.items[0].price).toBe(0);
});
});
});
Testability
AngularJS

describe("Shopping cart", function() {
describe("Checkout widget", function() {
// ...
it("should calculate order total", function() {
var scope = { items: [
{ price: 2, qty: 4 }, { price: 10, qty: 1 }
]};
var controller = new CheckoutController(scope);
expect(scope.total()).toBe(18);
});
});
});
¿jQuery...?
AngularJS + HTTP
Resources
$resource()
var Task = $resource("http://my.api/tasks/:id", {
id: "@id"
});
var newTask = new Task({
title: "New Task",
description: "..."
});
/* POST /tasks { "title": "New Task", ... } */
newPost.$save();
/* GET /tasks/5 */
var oneTask = Task.get({ id: 5 });
/* GET /tasks?completed=false&due=1381158984 */
var current = Task.query({
completed: false,
description: "..."
});
¡Muy mal!
¡No me gusta!
¡Eso es shinaniganos!
Tight coupling
Client-side URL templates
Excessive parameters
No links!
Intent
/tasks?
completed=false
&due=1381158984
No meaning
/tasks/current
/tasks/:id
$resource("/posts/:id", {id:
"@id"});
{
id: 5,
title: "Something New",
slug: "something-new"
}
/posts/something-new
...?
What to do?
uor/angular-model
(on GitHub) *

* Current code is old and broken, new release coming tomorrow
modelProvider.model("Tasks", {
$instance: {
finish: function() {
this.completed = true;
return this.$save();
},
isCompleted: function() {
return !!this.completed;
}
}
});
Where's the URL?
3 options
Automatic: /tasks
<link
rel="resource"
name="Tasks"
href="<?=$this->url('Tasks'); ?>"
/>
GET /
Accept:
application/vnd.resource-def+json
{
"Tasks": "http://my.app/tasks",
"Users": "http://my.app/users"
}
OPTIONS /tasks
Accept:
application/vnd.resourceschema+json
{
"title": "string",
"completed": "boolean",
...
}
More HTTP goodies
...that you don't need to
reinvent
HTTP Range
GET /rickroll.mp4
Range: bytes=10099999
HEAD /posts HTTP/1.1
...
HTTP 200 OK
Accept-Ranges: posts
GET /posts HTTP/1.1
Range: posts=1-20
HTTP Auth

Always use protection!
Caching

Implement any invalidation
strategy you can imagine
PHP?
nateabele/li3_resour
ces
(on GitHub)
Automatic CRUD manipulation with verbs
Parameter mapping
Links from model relationships
Schemas with OPTIONS
Proxies for mapping database values
Coming soon...
Range pagination
Smart search with ?q=...
...Tests (runs away)
Thanks!

2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando las reglas de la Web