REST
I am Brian Kaney from Vermonster LLC and will be presenting this talk on REST.
http://vermonster.com
github/twitter/irc: bkaney
What is REST?
● Conceived by Roy Fielding, author of the HTTP spec (1.0 and 1.1)
● An architecture (not a spec, not a standard)● Early implementation RFC5023 (Atom RSS)
● Op-ed: Wonderfully constraining way to view the web and conceive web applications
Characteristics
A web architecture where resources are stateless and exposed through (meaningful) URIs, manipulation is through a uniform interface and responses are self-descriptive.
Characteristics
A web architecture where resources are stateless and exposed through (meaningful) URIs, manipulation is through a uniform interface and responses are self-descriptive.
Huh?
Characteristics
A web architecture where resources are stateless and exposed through (meaningful) URIs, manipulation is through a uniform interface and responses are self-descriptive.
Resources: Sources of specifc information
Characteristics
A web architecture where resources are stateless and exposed through (meaningful) URIs, manipulation is through a uniform interface and responses are self-descriptive.
Stateless: Each request has all the information required, any state info is client-side.
Characteristics
A web architecture where resources are stateless and exposed through (meaningful) URIs, manipulation is through a uniform interface and responses are self-descriptive.
URIs: Identifcation of the representations of the resource.
Characteristics
A web architecture where resources are stateless and exposed through (meaningful) URIs, manipulation is through a uniform interface and responses are self-descriptive.
Uniform Interface: Common standard, like HTTP.
Characteristics
A web architecture where resources are stateless and exposed through (meaningful) URIs, manipulation is through a uniform interface and responses are self-descriptive.
Self-descriptive: Provides enough information as to how to process the response, like the content-type.
You might not be RESTful if...
Using HTTP with standard POST, GET, PUT requests, even with friendly URLs...and you still might not be using REST.
Anti-patterns to look for:● Using GET for non-retrieval● Using POST for “transport protocol”● No-cache● Ignoring status codes● Ignoring MIME and headers● No Hypermedia, link representations
Contrast to RPC
● Remote procedure calls● Not stateless● Not uniform
getCar(), updateCarAttributes(stuff), deleteCarsForManufacturer(mfg)
● Snowball into things like SOAP and WSDL that help automate discovery and describe what they do
● It's very Enterprisey
Contrast to RPC
GET /cars
Contrast to RPC
Once you even nod slightly toward calling remote procedures, you've abandoned the stateless beauty of the web and there is no turning back!!!
Contrast to RPC
Once you even nod slightly toward calling remote procedures, you've abandoned the stateless beauty of the web and there is no turning back!!!
But “foolish consistency is the hobgoblin of little minds”
- Ralph Waldo Emersoni.e. (cookies) – sparingly
Idempotent Operations
Same operation with same parameters
=> same outcome
● Get● Update● Delete
HATEOAS
● Hypermedia as the Engine of Application State
● Roy Fielding (again)● Instead of WSDLs, the hypermedia in
responses describes what can be done
● HATEOAS is a fantastic UI/UX principal for humans too
● HATEOAS complements integration testing
HATEOAS – Semantic Linking
● GET a single resource, it describes all actions that could be done on it.
curl -H “Accept: application/xml” http://host/cars/rabbit–<car> <make>VW</make> <model>Rabbit</model> <description>Entry-level hatchback...</description> <link rel=“trim” content-type=“application/xml” href=“http://host/cars/rabbit/trim”/> <link rel=“tech” content-type=“application/xml” href=“http://host/cars/rabbit/tech”/></car>
curl -H “Accept: application/xml” http://host/cars/rabbit–<car> <make>VW</make> <model>Rabbit</model> <description>Entry-level hatchback...</description> <link rel=“trim” content-type=“application/xml” href=“http://host/cars/rabbit/trim”/> <link rel=“tech” content-type=“application/xml” href=“http://host/cars/rabbit/tech”/></car>
HATEOAS – Semantic Linking (for Humans)
● GET a single resource, it draw links to all actions on single page.
curl -H “Accept: text/html” http://host/cars/rabbit–<html> <title>Rabbit</title> <body> <h1>Rabbit</h1>
<dl> <dt>Make</dt><dd>VW</dd> <dt>Model</dt><dd>Rabbit</dd> <dt>Description</dt><dd>Entry-level hatchback...</dd></dl><p><a rel=“trim” href=“http://host/cars/rabbit/trim”>Trim</a></p><p><a rel=“tech” href=“http://host/cars/rabbit/tech”>Tech</a></p>
</body></html>
curl -H “Accept: text/html” http://host/cars/rabbit–<html> <title>Rabbit</title> <body> <h1>Rabbit</h1>
<dl> <dt>Make</dt><dd>VW</dd> <dt>Model</dt><dd>Rabbit</dd> <dt>Description</dt><dd>Entry-level hatchback...</dd></dl><p><a rel=“trim” href=“http://host/cars/rabbit/trim”>Trim</a></p><p><a rel=“tech” href=“http://host/cars/rabbit/tech”>Tech</a></p>
</body></html>
HTTP – Uniform Interface
REST often uses HTTP. We all really like HTTP because it is:● Stateless● Scalable● Cachable● Proxieable● We already use it and have tons of
infrastructure to support it.
HTTP – Uniform Interface
REST often uses HTTP. We all really like HTTP because it is:● Stateless● Scalable● Cachable● Proxieable● We already use it and have tons of
infrastructure to support it.
HTTP Verbs (you've seen these)
Common HTTP Verb Table:
POST create /cars Create resource,post to collection
GET show /cars/1
PUT update /cars/1 Update new or existing resource*
DELETE destroy /cars/1
* REST sez... If I want to prescribe the identifer, I can PUT to the URI, regardless if the resource already exists.
HTTP Verbs (some you might not have seen)
Common HTTP Verb Table:
POST create /cars Create resource,post to collection
GET show /cars/1
PUT update /cars/1 Update new or existing resource
DELETE destroy /cars/1
HEAD info /cars/1 Same as show, no body
OPTIONS options /cars/1 Server options
TRACE loop-back /cars/1 Loop-back of request, test chain of proxies
Less-familiar verbs (in Rails circles at least):
HTTP Verbs
Common HTTP Verb Table:
POST create /cars Create resource,post to collection
GET show /cars/1
PUT update /cars/1 Update new or existing resource
DELETE destroy /cars/1
HEAD info /cars/1 Same as show, no body
OPTIONS options /cars/1 Server options
TRACE loop-back /cars/1 Loop-back of request, test chain of proxies
Less-familiar verbs (in Rails circles at least):
HTTP Verbs “100 Continue”
HEAD /cars/11
Client
HTTP Verbs “100 Continue”
HEAD /cars/11
100 ContinueClient Server2
HTTP Verbs “100 Continue”
HEAD /cars/11
100 Continue
PUT /cars/1[ a bunch of data ]
3
Client Server2
Used when sending fles / multipart form / octet-streamSupported by Unicorn (Rainbows!)
HTTP Response Status Codes
http://webmachine.basho.com/diagram.html
Rackanyone?
Response Status Codes
● Fairly simple to test and usehttp://github.com/rack/rack/blob/master/lib/rack/utils.rb#L369
## application_controller.rb
def permission_denied render :text => “403 Forbidden”, :status => :forbiddenend
## features/forbidden.feature
Scenario: Forbidden page When I visit forbidden page Then I should be forbidden
## features/custom_steps.rb
Then /^I should be forbidden$/ do page.driver.response.status.should == 403end
## application_controller.rb
def permission_denied render :text => “403 Forbidden”, :status => :forbiddenend
## features/forbidden.feature
Scenario: Forbidden page When I visit forbidden page Then I should be forbidden
## features/custom_steps.rb
Then /^I should be forbidden$/ do page.driver.response.status.should == 403end
Headers
● Great place for sending and receiving metadata including your own● X-My-Custom-Header “foo”
● Accept* headers● curl is your friend
curl -i -X GET \ -H "Accept: application/xml" \ -H “Accept-Language: es-US” \ http://server/resources/key
curl -i -X GET \ -H "Accept: application/xml" \ -H “Accept-Language: es-US” \ http://server/resources/key
Caching with Etags
ClientClient ServerServer
GET /cars/rabbit
Caching with Etags
ClientClient ServerServer
GET /cars/rabbit
HTTP/1.1 200 OKETag: 109h-402-f09h
Caching with Etags
ClientClient ServerServer
GET /cars/rabbit
HTTP/1.1 200 OKETag: 1f09-402-f09h
GET /cars/rabbitIf-None-Match: “1f09-402-f09h”
HTTP/1.1 301 Not ModifiedETag: 1f09-402-f09hContent-Length: 0
Security
● Mainly SSL● Stateless, send with each request● Slight deviation with sessions to make
human web apps more usable (and the bookmark case)
● Others, but not universal unless the can be adapted to use HTTP headers
Protocol Buffers
http://code.google.com/p/protobuf/
● Google projects● Simple message format● Binary, but language agnostic● Enterprisey – And wicked fast!
Meaningful Keys
● Rails, more specifcally AR, doesn't like not relying on auto-generated identifers
● Humans like identifers that are meaningful on their face
● Machines do to (primary index for free)● Ripple :key_on
Rails and REST
● The Rails machinery tries to promote REST, but that doesn't mean that all Rails applications are RESTful
● Routing: resource, resources
## config/routes.rb
MyApp::Application.routes.draw do resources :cars do resource :engine endend
## config/routes.rb
MyApp::Application.routes.draw do resources :cars do resource :engine endend
From Design to Code
● Identify which frst-class resource is being represented
● Turn verbs into nouns (roughly)E.g. If you want to “ship” some packages, consider creating a shipment resource that has_many packages.
● Creating a collection of objects, PUT to the parent using accepts-nested-attributes-for
● Rule of thumb – don't go more than 2 deep when nesting resources
ANAF● Accepts-nested-attributes-for
● Thin out controller logic
● Useful pattern in Rails, felds_for helper
## config/routes.rbMyApp::Application.routes.draw do resources :manufacturers do resource :models endend
## app/models/manufacturer.rbclass Manufacturer has_many :models accepts_nested_attributes_for :modelsend
## app/views/manufacturers/show.html.haml- form_for @manufacturer do |f| - fields_for :models do |ff| = ff.text_field :name
## config/routes.rbMyApp::Application.routes.draw do resources :manufacturers do resource :models endend
## app/models/manufacturer.rbclass Manufacturer has_many :models accepts_nested_attributes_for :modelsend
## app/views/manufacturers/show.html.haml- form_for @manufacturer do |f| - fields_for :models do |ff| = ff.text_field :name
Multi-step Form
Query parameters for view logic:
1. GET http://host/products/new
<h1>Select Category:</h1>
Multi-step Form
Query parameters for view logic:
1. GET http://host/products/new
<h1>Select Category:</h1>
2. GET http://host/products/new?cat=laptops
<h1>Category: Laptops, Select Size:</h1>
Multi-step Form
Query parameters for view logic:
1. GET http://host/products/new
<h1>Select Category:</h1>
2. GET http://host/products/new?cat=laptops
<h1>Category: Laptops, Select Size:</h1>
3. GET http://host/products/new?cat=laptops&size=17in
<h1>Category: Laptops, Size: 17in. Product Details:</h1>
Multi-step Form
Query parameters for view logic:
1. GET http://host/products/new
<h1>Select Category:</h1>
2. GET http://host/products/new?cat=laptops
<h1>Category: Laptops, Select Size:</h1>
3. GET http://host/products/new?cat=laptops&size=17in
<h1>Category: Laptops, Size: 17in. Product Details:</h1>
4. POST http://host/products [form data]
Inherited Resources● José Valim – Now part of Rails core. Also
wrote responders (part of Rails 3)● Convention over confguration, like Rails● Very DRY, thin controllers● Easy to override● Saves on controller unit tests
Before and After IR
<code>
IR Overriding Defaults
● Beginning of association chain● End of association chain● Build resource● Collections
<code>
● Responders (use i18n ./confg/locales/en.yaml to override fash messages)
Vision of the Future
● Every presentation ought to have one
MM VV CC Model View Controller
Vision of the Future
● Every presentation ought to have one
MM VV CC
MM RR ECEC+
Model View Controller
< becomes >
Model Resource + Enhanced Client
Vision of the Future
● Every presentation ought to have one
*EC – Pending marketing review
MM VV CC
MM RR ECEC+
Model View Controller
< becomes >
Model Resource + Enhanced Client
The Future is Now: Restfuliehttp://github.com/caelum/restfulie
● Manages Accept* headers better than Rails● Uses “tokamak” view fles to create proper
rel links.● Can be used along side of IR
<code>
Thanks