1. CakeFest 2012
Create a RESTful api
Sept 1, 2012
CakeFest 2012 Manchester
2. INTRODUCTION
Marc Ypes
@Ceeram
CakePHP 4 years
Core team 1.5 years
Undercover as programmer
CakeFest 2012 Manchester
3. OVERVIEW
REST my case?
REST your Cake
■ Content-type
■ Routing
■ Interface
■ Authentication
■ Cache
■ Errors
CakeFest 2012 Manchester
4. INTRODUCTION TO REST
Representational state transfer
Set of architectural principles
- resource focussed
- manipulation through representations
- HTTP protocol?
CakeFest 2012 Manchester
5. INTRODUCTION TO REST
Constraints
■ Client-server
■ Stateless
■ Uniform interface
■ Cacheable
■ Layered system
CakeFest 2012 Manchester
6. INTRODUCTION TO REST
Uniform interface
■ resource
■ identification of the resource
■ manipulation through representation
■ self-descriptive
■ hypermedia as the engine of application state
HATEOAS
CakeFest 2012 Manchester
7. INTRODUCTION TO REST
Uniform Interface
Data element Example
resource user, book etc. (users, books etc.)
resource identifier URL, URN (/users/1234)
representation
data TXT / HTML / XML /YAML,JSON
metadata content type, last-modified time
resource metadata source link, alternate
control data if-modified-since, cache-control, etag
http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
CakeFest 2012 Manchester
8. INTRODUCTION TO REST
Uniform Interface
/api/getUserProfile/1234
/api/addVoteForUser?id=1234
/api/users?action=vote&id=1234
/api/deleteUser/1
/api/deleteUser?id=1
/api/favoritedUsers
/api/getUserData/1?fields=name,email
CakeFest 2012 Manchester
9. INTRODUCTION TO REST
Uniform Interface
GET /users Get collection
POST /users Add to collection
GET /users/1234 Get resource
PUT /users/1234 Update resource
DELETE /users/1234 Delete resource
Update is not update?
POST /users/1234
CakeFest 2012 Manchester
13. INTRODUCTION TO REST
Uniform Interface
Safe methods
Idempotent methods
GET (HEAD) is safe (nullipotent)
PUT, DELETE are idempotent
POST
PATCH?
CakeFest 2012 Manchester
14. INTRODUCTION TO REST
Uniform Interface
Normalize the resources
GET /books/1849511926/votes
GET /votes?book=1849511926
CakeFest 2012 Manchester
15. INTRODUCTION TO REST
Uniform Interface
Normalize the resources
POST /books/1849511926/votes
PUT /books/1849511926
data contains votes subresource data
POST /votes
data is book=1849511926
CakeFest 2012 Manchester
16. INTRODUCTION TO REST
Uniform Interface
PATCH
Edge Rails: PATCH is the new primary HTTP method for updates
http://weblog.rubyonrails.org/2012/2/25/edge-rails-patch-is-the-new-primary-http-method-for-updates/
CakeFest 2012 Manchester
17. INTRODUCTION TO REST
Uniform Interface / HATEOAS
Level 3 of REST maturity model (RMM)
CakeFest 2012 Manchester
18. INTRODUCTION TO REST
Uniform Interface / HATEOAS
Level 0
Single URI, single HTTP method
CakeFest 2012 Manchester
19. INTRODUCTION TO REST
Uniform Interface / HATEOAS
Level 1
Many URI, single HTTP method
CakeFest 2012 Manchester
20. INTRODUCTION TO REST
Uniform Interface / HATEOAS
Level 2
Many URI, different HTTP methods
CakeFest 2012 Manchester
21. INTRODUCTION TO REST
Uniform Interface / HATEOAS
Level 2
Many URI, different HTTP methods
CakeFest 2012 Manchester
22. INTRODUCTION TO REST
Uniform Interface / HATEOAS
Level 3
Self descriptive
■ Media types
■ Links
■ Other protocols
CakeFest 2012 Manchester
23. INTRODUCTION TO REST
Uniform Interface / HATEOAS
HATEOAS
GET /comments?book=1849511926
Link to api.amazin.com/books/1849511926
Links to all comments
CakeFest 2012 Manchester
24. INTRODUCTION TO REST
Uniform Interface / HATEOAS
>GET /comments/1
<HTTP/1.1 200 Ok
<Content-Type: text/xml
<?xml version="1.0">
<comment>
<foo>great book</foo>
<book>
<link href="/books/1849511926" title="wow" />
</book>
</vote>
CakeFest 2012 Manchester
26. INTRODUCTION TO REST
Uniform Interface / HATEOAS
Link header
Link: <https://api.github.com/user/repos?page=2&per_page=100>;rel="
next",
<https://api.github.com/user/repos?page=50&per_page=100>;rel="last"
github.com
CakeFest 2012 Manchester
27. INTRODUCTION TO REST
Uniform Interface / Errors
HTTP Statuscodes
Human reads message
Code reads code
CakeFest 2012 Manchester
28. INTRODUCTION TO REST
Uniform Interface / Errors
HTTP Statuscodes
200 OK
201 Created
204 No Content
304 Not Modified
400 Bad Request
401 Unauthorized
404 Not Found
405 Method Not Allowed
CakeFest 2012 Manchester
29. INTRODUCTION TO REST
Uniform Interface / Errors
Link to support page
Link: <http://api.amazin.com/errors/405>; rel="help"
CakeFest 2012 Manchester
30. INTRODUCTION TO REST
Cacheable
HTTP Cache headers
Use them!
CakeFest 2012 Manchester
31. INTRODUCTION TO REST
Cacheable
HTTP Cache headers
Cache-control
- private
- public
- max-age / s-maxage
- must-revalidate
- nocache
CakeFest 2012 Manchester
33. INTRODUCTION TO REST
REST might not be what you are looking for
Questions?
Rest my Cake
CakeFest 2012 Manchester
34. REST my Cake
Basic setup
Route urls with extensions
http://localhost/cats/index.json
app/Config/routes.php
<?php
// allow any url extension
Router::parseExtensions();
//or allow .json extension only
Router::parseExtensions('json');
CakeFest 2012 Manchester
35. REST my Cake
Basic setup
Add RequestHandler component
<?php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $components = array(
'DebugKit.Toolbar',
'Session',
'RequestHandler',
);
}
CakeFest 2012 Manchester
36. REST my Cake
Basic setup
Create view files, the CakePHP 1.3 way (almost)
app/View/Cats/json/index.ctp
<?php echo json_encode($cats) ;?>
CakeFest 2012 Manchester
37. REST my Cake
Basic setup
Use auto serialization, the CakePHP 2.x way
public function view($id = null) {
$this->Cat->id = $id;
if (!$this->Cat->exists()) {
throw new NotFoundException(__('Invalid cat'));
}
$this->set('cat', $this->Cat->read(null, $id));
$this->set('_serialize', array('cat'));
}
CakeFest 2012 Manchester
38. REST my Cake
http://localhost/cats/index.json
CakeFest 2012 Manchester
39. REST my Cake
http://localhost/cats/view/1.json
CakeFest 2012 Manchester
40. REST my Cake
REST Routing
Resource mapping
http://localhost/cats
http://localhost/cats/1
app/Config/routes.php
Router::mapResources(array('Cats', 'Users'));
CakeFest 2012 Manchester
41. REST my Cake
REST Routing
Resource mapping
GET /cats index()
POST /cats add()
GET /cats/1 view(1)
POST /cats/1 edit(1)
PUT /cats/1 edit(1)
DELETE /cats/1 delete(1)
CakeFest 2012 Manchester
42. REST my Cake
REST Routing
Resource mapping
X-HTTP-Method-Override
<Limit PUT DELETE>
order deny,allow
allow from all
</Limit>
CakeFest 2012 Manchester
44. REST my Cake
REST Routing
Resource mapping
app/Config/routes.php
Router::mapResources(
array('Cats', 'Users', 'Pizza.Orders')
);
/cats => CatsController::index() in app
/users => UsersController::index() in app
/pizza/orders => OrdersController::index() in Pizza plugin
CakeFest 2012 Manchester
45. REST my Cake
REST Routing
Resource mapping
app/Config/routes.php
Router::mapResources(
array('Cats', 'Users', 'Pizza.Orders'),
array('prefix' => '/api/')
);
/api/cats => CatsController::index() in app
/api/users => UsersController::index() in app
/api/orders => OrdersController::index() in Pizza plugin
CakeFest 2012 Manchester
46. REST my Cake
REST Routing
Resource mapping
app/Config/routes.php
Router::mapResources(
array('Cats', 'Users', 'Pizza.Orders'),
array('prefix' => '/api/, 'id' => Router::UUID')
);
/api/cats => CatsController::index() in app
/api/users => UsersController::index() in app
/api/orders => OrdersController::index() in Pizza plugin
CakeFest 2012 Manchester
47. REST my Cake
REST Routing
.json
?format=json
curl -H "Accept: application/json" http://localhost/cats
CakeFest 2012 Manchester
48. REST my Cake
REST Routing
GET /cats/sleeping
GET /cats?status=sleeping
GET /cats?sleeping=1
GET /posts/recent
GET /posts?type=recent
CakeFest 2012 Manchester
49. REST my Cake
REST Routing
/posts/foo/bar routes with passed params
/posts/foo:bar routes with named params
app/Config/routes.php
Router::connect('/api/cats/*',
array(
'plugin' => null,
'controller' => 'posts',
'action' => 'index',
'[method]' => 'GET'
));
CakeFest 2012 Manchester
50. REST my Cake
REST Routing
GET /users/vote/1234
POST /users/vote/1234 $this->Html->postLink()
POST /api/users/1234/votes
public function vote($id = null) {
//user id exist, httpmethod checks etc.
$this->User->updateAll(
array('User.votes' => 'User.votes + 1'),
array('User.id' => $id)
);
}
CakeFest 2012 Manchester
52. REST my Cake
REST Routing
POST /users/1234/votes
public function vote($id = null) {
//user id exist checks etc
$this->User->Vote->add($id);
}
POST /votes
public function add() {
$this->Vote->add($this->request->data['Vote.
user']);
}
CakeFest 2012 Manchester
53. REST my Cake
REST Routing
CakeRequest::addDetector(
'patch',
array(
'env' => 'REQUEST_METHOD',
'value' => 'PATCH'
));
CakeFest 2012 Manchester