Date post: | 10-May-2015 |
Category: |
Technology |
Upload: | php-conference-argentina |
View: | 3,924 times |
Download: | 0 times |
HTTP ALL THE THINGSSimplifying Rich Applications byRespecting the Rules of the Web
Me
Nate Abele
Former lead developer, CakePHP
Founder & current lead developer, Lithium
Member, AngularUI
@nateabele
History
1998: SOAP & XML-RPC
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 bindingjQuery
<input type="text" id="name" /><h1>Hello!</h1>
<script type="text/javascript">
</script>
$(document).ready(function() { $('#name').keydown(function(e) { $('h1').html("Hello " + e.target.value + "!") }); });
Event bindingAngularJS
<input type="text" ng-model="name" />
<h1>Hello {{ name }}!</h1>
Hello !
IterationjQuery
<ul class="greetings"></ul>
<script type="text/javascript">
</script>
$(["Hello", "Hola", "Ciao"]).each(function(k, v) { $(".greeting").append("<li>" + v + " World</li>" });
IterationAngularJS
<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
OrganizationAngularJS
Item: Qty: 0 Price: 0 Total: $0.00
Total: $0.00
OrganizationAngularJS
<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>
OrganizationAngularJS
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;
});
};
}
OrganizationjQuery
¿Ummm...?
OrganizationjQuery
*shrug*
TestabilityAngularJS
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);
});
});
});
TestabilityAngularJS
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 + HTTPResources
$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.resource-
schema+json
{
"title": "string",
"completed": "boolean",
...
}
More HTTP goodies...that you don't need to
reinvent
HTTP Range
GET /rickroll.mp4
Range: bytes=100-99999
HEAD /posts HTTP/1.1
...
HTTP 200 OK
Accept-Ranges: posts
GET /posts HTTP/1.1
Range: posts=1-20
HTTP AuthAlways use protection!
CachingImplement any invalidationstrategy you can imagine
PHP?
nateabele/li3_resources
(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!