Upload
fabio-akita
View
9.146
Download
0
Embed Size (px)
Citation preview
Making Rails really RestfulImproving the world of Resources on Rails with Restfulie
Fabio Akita - akitaonrails.com - @akitaonrails
Wednesday, June 9, 2010
The greatest thing about talking to you
Wednesday, June 9, 2010
We’ve been through this already!
Wednesday, June 9, 2010
We’ve been through this already!
No WSDL and WS-*
Wednesday, June 9, 2010
We’ve been through this already!
No WSDL and WS-*No XML-RPC
Wednesday, June 9, 2010
We’ve been through this already!
No WSDL and WS-*No XML-RPC
No $$ enterprisey stuff
Wednesday, June 9, 2010
We’ve been through this already!
No WSDL and WS-*No XML-RPC
No $$ enterprisey stuff
♥ HTTP
Wednesday, June 9, 2010
♥ HTTP
Wednesday, June 9, 2010
♥ HTTP
Shared Nothing Architecture
Wednesday, June 9, 2010
♥ HTTP
Shared Nothing ArchitectureStateless
Wednesday, June 9, 2010
♥ HTTP
Shared Nothing ArchitectureStateless
Caching
Wednesday, June 9, 2010
♥ HTTP
Shared Nothing ArchitectureStateless
CachingProxies and Reverse Proxies
Wednesday, June 9, 2010
♥ HTTP
Shared Nothing ArchitectureStateless
CachingProxies and Reverse Proxies
Wednesday, June 9, 2010
Discovering a world of
Resources on RailsDavid Heinemeir Hansson RailsConf 2006
Wednesday, June 9, 2010
Create Read Update Delete
Wednesday, June 9, 2010
Wednesday, June 9, 2010
GET POST PUT DELETE
!nd create update destroy
SELECT INSERT UPDATE DELETE
Wednesday, June 9, 2010
GET POST PUT DELETE
!nd create update destroy
SELECT INSERT UPDATE DELETE
Wednesday, June 9, 2010
GET POST PUT DELETE
!nd create update destroy
SELECT INSERT UPDATE DELETE
Wednesday, June 9, 2010
GET POST PUT DELETE
!nd create update destroy
SELECT INSERT UPDATE DELETE
Wednesday, June 9, 2010
POST /people/createGET /people/show/1POST /people/update/1POST /people/destroy/1
Wednesday, June 9, 2010
POST /peopleGET /people/1PUT /people/1DELETE /people/1
Wednesday, June 9, 2010
MyApp::Application.routes.draw do |map| resources :peopleend
Wednesday, June 9, 2010
class PeopleController < ApplicationController # POST /people/1 # POST /people/1.xml def create end
# GET /people # GET /people.xml def show end
# PUT /people/1 # PUT /people/1.xml def update end
# DELETE /people/1 # DELETE /people/1.xml def destroy endend
form_for(@person) do |f| f.text_field :nameend
Wednesday, June 9, 2010
class PeopleController < ApplicationController # POST /people/1 # POST /people/1.xml def create end
# GET /people # GET /people.xml def show end
# PUT /people/1 # PUT /people/1.xml def update end
# DELETE /people/1 # DELETE /people/1.xml def destroy endend
link_to 'Show', person
Wednesday, June 9, 2010
class PeopleController < ApplicationController # POST /people/1 # POST /people/1.xml def create end
# GET /people # GET /people.xml def show end
# PUT /people/1 # PUT /people/1.xml def update end
# DELETE /people/1 # DELETE /people/1.xml def destroy endend
form_for(@person) do |f| f.text_field :nameend
Wednesday, June 9, 2010
class PeopleController < ApplicationController # POST /people/1 # POST /people/1.xml def create end
# GET /people # GET /people.xml def show end
# PUT /people/1 # PUT /people/1.xml def update end
# DELETE /people/1 # DELETE /people/1.xml def destroy endend
link_to 'Destroy', person, :method => :delete
Wednesday, June 9, 2010
Answering to mime types
Wednesday, June 9, 2010
Answering to mime types
One controller for many clients
Wednesday, June 9, 2010
Answering to mime types
One controller for many clientsOne action returning different representations
Wednesday, June 9, 2010
Answering to mime types
One controller for many clientsOne action returning different representations
“Content Negotiation"
Wednesday, June 9, 2010
class PeopleController < ApplicationController def index @people = Person.all
respond_to do |format| format.html # index.html.erb format.js # index.js.erb format.atom # index.atom.builder format.xml { render :xml => @people } end endend
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def index @people = Person.all respond_with(@people) endend
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def index @people = Person.all respond_with(@people) endend
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def index @people = Person.all respond_with(@people) endend
GET /people=> returns HTML
GET /people.xml=> returns XML
Accept: text/javascriptGET /people=> returns JS
Accept: text/xmlGET /people=> returns XML
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def index @people = Person.all respond_with(@people) endend
GET /people=> returns HTML
GET /people.xml=> returns XML
Accept: text/javascriptGET /people=> returns JS
Accept: text/xmlGET /people=> returns XML
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def index @people = Person.all respond_with(@people) endend
GET /people=> returns HTML
GET /people.xml=> returns XML
Accept: text/javascriptGET /people=> returns JS
Accept: text/xmlGET /people=> returns XML
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def index @people = Person.all respond_with(@people) endend
GET /people=> returns HTML
GET /people.xml=> returns XML
Accept: text/javascriptGET /people=> returns JS
Accept: text/xmlGET /people=> returns XML
Wednesday, June 9, 2010
2008Rails 2.2
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def show @person = Person.find(params[:id]) if stale?(:etag => @person, :last_modified => @person.created_at.utc, :public => true) respond_with @person end endend
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def show @person = Person.find(params[:id]) if stale?(:etag => @person, :last_modified => @person.created_at.utc, :public => true) respond_with @person end endend
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def show @person = Person.find(params[:id]) if stale?(:etag => @person, :last_modified => @person.created_at.utc, :public => true) respond_with @person end endend
GET /people/1
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def show @person = Person.find(params[:id]) if stale?(:etag => @person, :last_modified => @person.created_at.utc, :public => true) respond_with @person end endend
GET /people/1=> returns:
HTTP/1.1 200 OK Etag: "fd19b85b6ba49b5778de34310d141319"Last-Modified: Fri, 21 May 2010 05:31:11 GMTContent-Type: text/html; charset=utf-8Cache-Control: public...
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def show @person = Person.find(params[:id]) if stale?(:etag => @person, :last_modified => @person.created_at.utc, :public => true) respond_with @person end endend
GET /people/1=> returns:
HTTP/1.1 200 OK Etag: "fd19b85b6ba49b5778de34310d141319"Last-Modified: Fri, 21 May 2010 05:31:11 GMTContent-Type: text/html; charset=utf-8Cache-Control: public...
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def show @person = Person.find(params[:id]) if stale?(:etag => @person, :last_modified => @person.created_at.utc, :public => true) respond_with @person end endend
If-None-Match: "fd19b85b6ba49b5778de34310d141319"GET /people/1
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def show @person = Person.find(params[:id]) if stale?(:etag => @person, :last_modified => @person.created_at.utc, :public => true) respond_with @person end endend
If-None-Match: "fd19b85b6ba49b5778de34310d141319"GET /people/1
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def show @person = Person.find(params[:id]) if stale?(:etag => @person, :last_modified => @person.created_at.utc, :public => true) respond_with @person end endend
If-None-Match: "fd19b85b6ba49b5778de34310d141319"GET /people/1=> returns:
HTTP/1.1 304 Not Modified Etag: "fd19b85b6ba49b5778de34310d141319"Last-Modified: Fri, 21 May 2010 05:31:11 GMTCache-Control: public...
Wednesday, June 9, 2010
class PeopleController < ApplicationController respond_to :html, :js, :xml def show @person = Person.find(params[:id]) if stale?(:etag => @person, :last_modified => @person.created_at.utc, :public => true) respond_with @person end endend
If-None-Match: "fd19b85b6ba49b5778de34310d141319"GET /people/1=> returns:
HTTP/1.1 304 Not Modified Etag: "fd19b85b6ba49b5778de34310d141319"Last-Modified: Fri, 21 May 2010 05:31:11 GMTCache-Control: public...
Wednesday, June 9, 2010
But!
Wednesday, June 9, 2010
CRUD is not a goal,it’s an aspiration,
a design technique
Wednesday, June 9, 2010
And we are not done yet!
Wednesday, June 9, 2010
Why not?
ConsistencySimplicity
Discoverability
Wednesday, June 9, 2010
Why not?
ConsistencySimplicity
Discoverability
Wednesday, June 9, 2010
Why not?
ConsistencySimplicity
Discoverability
Wednesday, June 9, 2010
This is NOT necessarily REST
Wednesday, June 9, 2010
This is NOT necessarily REST
Using HTTP
Wednesday, June 9, 2010
This is NOT necessarily REST
Using HTTPUsing HTTP Verbs (PUT, DELETE)
Wednesday, June 9, 2010
This is NOT necessarily REST
Using HTTPUsing HTTP Verbs (PUT, DELETE)
Pretty URIs
Wednesday, June 9, 2010
Most of what we call “REST” is not REST
Wednesday, June 9, 2010
REST Principles
Wednesday, June 9, 2010
REST Principles
Identi"cation of Resources
Wednesday, June 9, 2010
REST Principles
Identi"cation of ResourcesManipulate resources through representations
Wednesday, June 9, 2010
REST Principles
Identi"cation of ResourcesManipulate resources through representations
Self-descriptive messages
Wednesday, June 9, 2010
REST Principles
Identi"cation of ResourcesManipulate resources through representations
Self-descriptive messagesHATEOAS
Wednesday, June 9, 2010
REST Goals
Wednesday, June 9, 2010
REST Goals
Scalability of component interactions
Wednesday, June 9, 2010
REST Goals
Scalability of component interactionsGenerality of interfaces
Wednesday, June 9, 2010
REST Goals
Scalability of component interactionsGenerality of interfaces
Independent deployment of components
Wednesday, June 9, 2010
REST Goals
Scalability of component interactionsGenerality of interfaces
Independent deployment of componentsReduce latency, enforce security
Wednesday, June 9, 2010
REST Goals
Scalability of component interactionsGenerality of interfaces
Independent deployment of componentsReduce latency, enforce security
http://en.wikipedia.org/wiki/Representational_State_Transfer#Guiding_principles_of_a_REST_interface
Wednesday, June 9, 2010
Constraints are liberating(a straight jacket for your mind)
Wednesday, June 9, 2010
Wednesday, June 9, 2010
What are we doing right?
Wednesday, June 9, 2010
What are we doing right?
Uniform Interface (URI Templates)
Wednesday, June 9, 2010
What are we doing right?
Uniform Interface (URI Templates)HTTP Verbs (some)
Wednesday, June 9, 2010
What are we doing right?
Uniform Interface (URI Templates)HTTP Verbs (some)
HTTP Status Codes (some)
Wednesday, June 9, 2010
What are we doing right?
Uniform Interface (URI Templates)HTTP Verbs (some)
HTTP Status Codes (some)Content Negotiation
Wednesday, June 9, 2010
What is missing?
Wednesday, June 9, 2010
What is missing?
More HTTP (verbs, status codes, headers)
Wednesday, June 9, 2010
What is missing?
More HTTP (verbs, status codes, headers)Hyperlinks
Wednesday, June 9, 2010
What is missing?
More HTTP (verbs, status codes, headers)Hyperlinks
Semantic (media-types)
Wednesday, June 9, 2010
GET POST DELETE
!nd create update destroy
SELECT INSERT UPDATE DELETE
PUT
Wednesday, June 9, 2010
GET POST DELETE
!nd create update destroy
SELECT INSERT UPDATE DELETE
POST
Wednesday, June 9, 2010
GET POST DELETE
!nd create update destroy
SELECT INSERT UPDATE DELETE
PATCH
Wednesday, June 9, 2010
GET POST PUT PATCH DELETE
!nd create replace update destroy
SELECT INSERT UPDATE UPDATE DELETE
RFC 5789 - http://www.innoq.com/blog/st/2010/03/rfc_5789_patch_method_for_http.html
Wednesday, June 9, 2010
Why bother?
Wednesday, June 9, 2010
Why bother?
Consistency
Wednesday, June 9, 2010
Why bother?
ConsistencySimplicity
Wednesday, June 9, 2010
Why bother?
ConsistencySimplicity
Discoverability
Wednesday, June 9, 2010
Richardson Restful ModelRichardson Restful Model
Level 3 Hypermedia
Level 2 HTTP
Level 1 URI
Wednesday, June 9, 2010
Richardson Restful ModelRichardson Restful Model
Level 3 Hypermedia
Level 2 HTTP
Level 1 URI
Wednesday, June 9, 2010
Richardson Restful ModelRichardson Restful Model
Level 3 Hypermedia
Level 2 HTTP
Level 1 URI
Wednesday, June 9, 2010
Richardson Restful ModelRichardson Restful Model
Level 3 Hypermedia
Level 2 HTTP
Level 1 URI
Wednesday, June 9, 2010
The Web as it is
Wednesday, June 9, 2010
The Web as it is
Wednesday, June 9, 2010
Evaluation Workflow
Wednesday, June 9, 2010
Evaluation WorkflowWhen there is a new app
Wednesday, June 9, 2010
Evaluation WorkflowWhen there is a new app
Then move forward to evaluate it
Wednesday, June 9, 2010
Evaluation WorkflowWhen there is a new app
Then move forward to evaluate it
When there is an app being evaluated
Wednesday, June 9, 2010
Evaluation WorkflowWhen there is a new app
Then move forward to evaluate it
When there is an app being evaluatedAnd the app passes the criteria
Wednesday, June 9, 2010
Evaluation WorkflowWhen there is a new app
Then move forward to evaluate it
When there is an app being evaluatedAnd the app passes the criteria
Then approve the app
Wednesday, June 9, 2010
Evaluation WorkflowWhen there is a new app
Then move forward to evaluate it
When there is an app being evaluatedAnd the app passes the criteria
Then approve the app
When there is an app being evaluated
Wednesday, June 9, 2010
Evaluation WorkflowWhen there is a new app
Then move forward to evaluate it
When there is an app being evaluatedAnd the app passes the criteria
Then approve the app
When there is an app being evaluated
And the app doesn't pass the criteria
Wednesday, June 9, 2010
Evaluation WorkflowWhen there is a new app
Then move forward to evaluate it
When there is an app being evaluatedAnd the app passes the criteria
Then approve the app
When there is an app being evaluated
And the app doesn't pass the criteriaThen decline the app
Wednesday, June 9, 2010
Wednesday, June 9, 2010
Wednesday, June 9, 2010
Wednesday, June 9, 2010
Wednesday, June 9, 2010
Wednesday, June 9, 2010
Wednesday, June 9, 2010
Wednesday, June 9, 2010
Wednesday, June 9, 2010
Wednesday, June 9, 2010
Wednesday, June 9, 2010
The Automated Web?
Wednesday, June 9, 2010
The Automated Web?
?
Wednesday, June 9, 2010
require 'rubygems'require 'mechanize'
agent = Mechanize.new { |agent| agent.user_agent_alias = "Mac Safari" }
agent.get("http://localhost:3000/apps?state=new")
Wednesday, June 9, 2010
require 'rubygems'require 'mechanize'
agent = Mechanize.new { |agent| agent.user_agent_alias = "Mac Safari" }
agent.get("http://localhost:3000/apps?state=new")
Wednesday, June 9, 2010
require 'rubygems'require 'mechanize'
agent = Mechanize.new { |agent| agent.user_agent_alias = "Mac Safari" }
agent.get("http://localhost:3000/apps?state=new")
Wednesday, June 9, 2010
agent.click agent.page.link_with(:href => /apps\/\d+/)
evaluate = agent.page.link_with(:text => /Evaluate/)agent.post evaluate.href, "" if evaluate
approve = agent.page.link_with :text => /Approve/ decline = agent.page.link_with :text => /Decline/
Wednesday, June 9, 2010
agent.click agent.page.link_with(:href => /apps\/\d+/)
evaluate = agent.page.link_with(:text => /Evaluate/)agent.post evaluate.href, "" if evaluate
approve = agent.page.link_with :text => /Approve/ decline = agent.page.link_with :text => /Decline/
Wednesday, June 9, 2010
agent.click agent.page.link_with(:href => /apps\/\d+/)
evaluate = agent.page.link_with(:text => /Evaluate/)agent.post evaluate.href, "" if evaluate
approve = agent.page.link_with :text => /Approve/ decline = agent.page.link_with :text => /Decline/
Wednesday, June 9, 2010
agent.click agent.page.link_with(:href => /apps\/\d+/)
evaluate = agent.page.link_with(:text => /Evaluate/)agent.post evaluate.href, "" if evaluate
approve = agent.page.link_with :text => /Approve/ decline = agent.page.link_with :text => /Decline/
Wednesday, June 9, 2010
if approve && decline description = agent.page.search("pre").text
if description =~ /Flash/ agent.post decline.href, ""
elsif description =~ /sex/ agent.post decline.href, ""
else agent.post approve.href, ""
end
end
Wednesday, June 9, 2010
if approve && decline description = agent.page.search("pre").text
if description =~ /Flash/ agent.post decline.href, ""
elsif description =~ /sex/ agent.post decline.href, ""
else agent.post approve.href, ""
end
end
Wednesday, June 9, 2010
if approve && decline description = agent.page.search("pre").text
if description =~ /Flash/ agent.post decline.href, ""
elsif description =~ /sex/ agent.post decline.href, ""
else agent.post approve.href, ""
end
end
Wednesday, June 9, 2010
if approve && decline description = agent.page.search("pre").text
if description =~ /Flash/ agent.post decline.href, ""
elsif description =~ /sex/ agent.post decline.href, ""
else agent.post approve.href, ""
end
end
Wednesday, June 9, 2010
No Mechanization?
Wednesday, June 9, 2010
No Mechanization?
Hyperlinks
Wednesday, June 9, 2010
No Mechanization?
HyperlinksNo Semantics
Wednesday, June 9, 2010
No Mechanization?
HyperlinksNo Semantics
Human Heuristics
Wednesday, June 9, 2010
require 'rubygems'require 'active_resource'
class App < ActiveResource::Base self.site = "http://localhost:3000/"end
apps = App.find(:all, :params => { :state => "new" })
Wednesday, June 9, 2010
require 'rubygems'require 'active_resource'
class App < ActiveResource::Base self.site = "http://localhost:3000/"end
apps = App.find(:all, :params => { :state => "new" })
GET /apps?state=new
Wednesday, June 9, 2010
require 'rubygems'require 'active_resource'
class App < ActiveResource::Base self.site = "http://localhost:3000/"end
apps = App.find(:all, :params => { :state => "new" })
GET /apps?state=new
Wednesday, June 9, 2010
require 'rubygems'require 'active_resource'
class App < ActiveResource::Base self.site = "http://localhost:3000/"end
apps = App.find(:all, :params => { :state => "new" })
GET /apps?state=new
Wednesday, June 9, 2010
require 'rubygems'require 'active_resource'
class App < ActiveResource::Base self.site = "http://localhost:3000/"end
apps = App.find(:all, :params => { :state => "new" })
GET /apps?state=new
Wednesday, June 9, 2010
ActionController::Routing::Routes.draw do |map| map.resources :apps, :member => { :evaluate => :post, :approve => :post, :decline => :post }end
POST /apps/1/evaluatePOST /apps/1/declinePOST /apps/1/approve
Wednesday, June 9, 2010
POST /apps/1/evaluatePOST /apps/1/declinePOST /apps/1/approve
app = apps.firstapp.post(:evaluate) if app.state == "new"
if apps.first.description =~ /Flash/ app.post(:decline)
elsif apps.first.description =~ /sex/ app.post(:decline)
else app.post(:approve)end
Wednesday, June 9, 2010
POST /apps/1/evaluatePOST /apps/1/declinePOST /apps/1/approve
app = apps.firstapp.post(:evaluate) if app.state == "new"
if apps.first.description =~ /Flash/ app.post(:decline)
elsif apps.first.description =~ /sex/ app.post(:decline)
else app.post(:approve)end
Wednesday, June 9, 2010
POST /apps/1/evaluatePOST /apps/1/declinePOST /apps/1/approve
app = apps.firstapp.post(:evaluate) if app.state == "new"
if apps.first.description =~ /Flash/ app.post(:decline)
elsif apps.first.description =~ /sex/ app.post(:decline)
else app.post(:approve)end
Wednesday, June 9, 2010
POST /apps/1/evaluatePOST /apps/1/declinePOST /apps/1/approve
app = apps.firstapp.post(:evaluate) if app.state == "new"
if apps.first.description =~ /Flash/ app.post(:decline)
elsif apps.first.description =~ /sex/ app.post(:decline)
else app.post(:approve)end
Wednesday, June 9, 2010
POST /apps/1/evaluatePOST /apps/1/declinePOST /apps/1/approve
app = apps.firstapp.post(:evaluate) if app.state == "new"
if apps.first.description =~ /Flash/ app.post(:decline)
elsif apps.first.description =~ /sex/ app.post(:decline)
else app.post(:approve)end
Wednesday, June 9, 2010
POST /apps/1/evaluatePOST /apps/1/declinePOST /apps/1/approve
app = apps.firstapp.post(:evaluate) if app.state == "new"
if apps.first.description =~ /Flash/ app.post(:decline)
elsif apps.first.description =~ /sex/ app.post(:decline)
else app.post(:approve)end
Wednesday, June 9, 2010
POST /apps/1/evaluatePOST /apps/1/declinePOST /apps/1/approve
app = apps.firstapp.post(:evaluate) if app.state == "new"
if apps.first.description =~ /Flash/ app.post(:decline)
elsif apps.first.description =~ /sex/ app.post(:decline)
else app.post(:approve)end
Wednesday, June 9, 2010
application/xml
<?xml version="1.0" encoding="UTF-8"?><app> <id type="integer">1</id> <title>Facebook</title> <updated_at type="datetime">2010-06-02T14:16:45Z</updated_at> <state>new</state> <description>Facebook for iPhone ... on the go.</description> <price type="float">0.0</price></app>
Wednesday, June 9, 2010
Why not ActiveResource?
Wednesday, June 9, 2010
Why not ActiveResource?
No Hyperlinks
Wednesday, June 9, 2010
Why not ActiveResource?
No HyperlinksNo Semantics
Wednesday, June 9, 2010
Why not ActiveResource?
No HyperlinksNo Semantics
Doesn’t respect HTTP (etag, last modi"ed)
Wednesday, June 9, 2010
Why not ActiveResource?
No HyperlinksNo Semantics
Doesn’t respect HTTP (etag, last modi"ed)Ruby on Rails only Conventions
Wednesday, June 9, 2010
Why not other web clients?HTTParty, RestClient, Typhoeus, Curb
Wednesday, June 9, 2010
Why not other web clients?
Most are not really “REST”
HTTParty, RestClient, Typhoeus, Curb
Wednesday, June 9, 2010
Why not other web clients?
Most are not really “REST”Just URI consumers
HTTParty, RestClient, Typhoeus, Curb
Wednesday, June 9, 2010
Why not other web clients?
Most are not really “REST”Just URI consumers
Wrappers for low level HTTP connections
HTTParty, RestClient, Typhoeus, Curb
Wednesday, June 9, 2010
One goal is to avoid tight coupling
Wednesday, June 9, 2010
http://restfulie.caelumobjects.com/
Wednesday, June 9, 2010
Restfulie
Wednesday, June 9, 2010
Restfulie
Client and Server solution
Wednesday, June 9, 2010
Restfulie
Client and Server solutionXML, JSON, Atom Representations
Wednesday, June 9, 2010
Restfulie
Client and Server solutionXML, JSON, Atom Representations
Enhances Ruby on Rails
Wednesday, June 9, 2010
Restfulie
Client and Server solutionXML, JSON, Atom Representations
Enhances Ruby on RailsREST Client
Wednesday, June 9, 2010
Restfulie
@guilhermesilveira
@caueguerra
@georgeguimaraes
@lfcipriani
Wednesday, June 9, 2010
app/controllers/apps_controller.rb
class AppsController < ApplicationController restfulie respond_to :html, :xml, :atom inherit_resources ...end
Wednesday, June 9, 2010
app/controllers/apps_controller.rb
class AppsController < ApplicationController restfulie respond_to :html, :xml, :atom inherit_resources ...end
Wednesday, June 9, 2010
app/controllers/apps_controller.rb
class AppsController < ApplicationController restfulie respond_to :html, :xml, :atom inherit_resources ...end
Wednesday, June 9, 2010
app/controllers/apps_controller.rb
class AppsController < ApplicationController restfulie respond_to :html, :xml, :atom inherit_resources ...end
Wednesday, June 9, 2010
app/controllers/apps_controller.rb
class AppsController < ApplicationController restfulie respond_to :html, :xml, :atom inherit_resources ...end
Wednesday, June 9, 2010
Tokamak
Wednesday, June 9, 2010
Tokamak
Wednesday, June 9, 2010
app/views/apps/index.tokamak
collection(@apps) do |collection| collection.values do |values| values.id apps_url values.title "Apps List" values.updated_at Time.now.utc end collection.members do |member, app| partial "member", :locals => { :member => member, :app => app } endend
Wednesday, June 9, 2010
app/views/apps/index.tokamak
collection(@apps) do |collection| collection.values do |values| values.id apps_url values.title "Apps List" values.updated_at Time.now.utc end collection.members do |member, app| partial "member", :locals => { :member => member, :app => app } endend
Wednesday, June 9, 2010
app/views/apps/_member.tokamak
member.values do |value| value.id app.id value.title app.name value.updated_at app.updated_at.utc value.state app.state value.description app.description value.price app.priceendmember.link "show", app_url(app) if app.state == "new" member.link "evaluate", evaluate_app_url(app)elsif app.state == "evaluating" member.link "approve", approve_app_url(app) member.link "decline", decline_app_url(app)end
Wednesday, June 9, 2010
app/views/apps/_member.tokamak
member.values do |value| value.id app.id value.title app.name value.updated_at app.updated_at.utc value.state app.state value.description app.description value.price app.priceendmember.link "show", app_url(app) if app.state == "new" member.link "evaluate", evaluate_app_url(app)elsif app.state == "evaluating" member.link "approve", approve_app_url(app) member.link "decline", decline_app_url(app)end
Wednesday, June 9, 2010
app/views/apps/_member.tokamak
member.values do |value| value.id app.id value.title app.name value.updated_at app.updated_at.utc value.state app.state value.description app.description value.price app.priceendmember.link "show", app_url(app) if app.state == "new" member.link "evaluate", evaluate_app_url(app)elsif app.state == "evaluating" member.link "approve", approve_app_url(app) member.link "decline", decline_app_url(app)end
Wednesday, June 9, 2010
app/views/apps/_member.tokamak
member.values do |value| value.id app.id value.title app.name value.updated_at app.updated_at.utc value.state app.state value.description app.description value.price app.priceendmember.link "show", app_url(app) if app.state == "new" member.link "evaluate", evaluate_app_url(app)elsif app.state == "evaluating" member.link "approve", approve_app_url(app) member.link "decline", decline_app_url(app)end
Wednesday, June 9, 2010
app/views/apps/_member.tokamak
member.values do |value| value.id app.id value.title app.name value.updated_at app.updated_at.utc value.state app.state value.description app.description value.price app.priceendmember.link "show", app_url(app) if app.state == "new" member.link "evaluate", evaluate_app_url(app)elsif app.state == "evaluating" member.link "approve", approve_app_url(app) member.link "decline", decline_app_url(app)end
Wednesday, June 9, 2010
app/views/apps/_member.tokamak
member.values do |value| value.id app.id value.title app.name value.updated_at app.updated_at.utc value.state app.state value.description app.description value.price app.priceendmember.link "show", app_url(app) if app.state == "new" member.link "evaluate", evaluate_app_url(app)elsif app.state == "evaluating" member.link "approve", approve_app_url(app) member.link "decline", decline_app_url(app)end
Wednesday, June 9, 2010
curl -H “Accept: application/atom+xml” http://localhost:3000/apps/1
<entry xmlns="http://www.w3.org/2005/Atom"> <id>1</id> <title>Facebook</title> <updated_at>2010-06-02T14:16:45Z</updated_at> <state>new</state> <description>Facebook for iPhone ... on the go. </description> <price>0.0</price> <link href="http://localhost:3000/apps/1" rel="show" type="application/atom+xml"/> <link href="http://localhost:3000/apps/1/evaluate" rel="evaluate" type="application/atom+xml"/></entry>
Wednesday, June 9, 2010
curl -H “Accept: application/atom+xml” http://localhost:3000/apps/1
<entry xmlns="http://www.w3.org/2005/Atom"> <id>1</id> <title>Facebook</title> <updated_at>2010-06-02T14:16:45Z</updated_at> <state>new</state> <description>Facebook for iPhone ... on the go. </description> <price>0.0</price> <link href="http://localhost:3000/apps/1" rel="show" type="application/atom+xml"/> <link href="http://localhost:3000/apps/1/evaluate" rel="evaluate" type="application/atom+xml"/></entry>
Wednesday, June 9, 2010
curl -H “Accept: application/atom+xml” http://localhost:3000/apps/1
<entry xmlns="http://www.w3.org/2005/Atom"> <id>1</id> <title>Facebook</title> <updated_at>2010-06-02T14:16:45Z</updated_at> <state>new</state> <description>Facebook for iPhone ... on the go. </description> <price>0.0</price> <link href="http://localhost:3000/apps/1" rel="show" type="application/atom+xml"/> <link href="http://localhost:3000/apps/1/evaluate" rel="evaluate" type="application/atom+xml"/></entry>
Wednesday, June 9, 2010
<?xml version="1.0"?><app> <id>1</id> <title>Facebook</title> <updated_at>2010-06-02T14:16:45Z</updated_at> <state>new</state> <description>Facebook for iPhone ... on the go. </description> <price>0.0</price> <link href="http://localhost:3000/apps/1" rel="show" type="application/xml"/> <link href="http://localhost:3000/apps/1/evaluate" rel="evaluate" type="application/xml"/></app>
curl -H “Accept: application/xml” http://localhost:3000/apps/1
Wednesday, June 9, 2010
<?xml version="1.0"?><app> <id>1</id> <title>Facebook</title> <updated_at>2010-06-02T14:16:45Z</updated_at> <state>new</state> <description>Facebook for iPhone ... on the go. </description> <price>0.0</price> <link href="http://localhost:3000/apps/1" rel="show" type="application/xml"/> <link href="http://localhost:3000/apps/1/evaluate" rel="evaluate" type="application/xml"/></app>
curl -H “Accept: application/xml” http://localhost:3000/apps/1
Wednesday, June 9, 2010
<?xml version="1.0"?><app> <id>1</id> <title>Facebook</title> <updated_at>2010-06-02T14:16:45Z</updated_at> <state>new</state> <description>Facebook for iPhone ... on the go. </description> <price>0.0</price> <link href="http://localhost:3000/apps/1" rel="show" type="application/xml"/> <link href="http://localhost:3000/apps/1/evaluate" rel="evaluate" type="application/xml"/></app>
curl -H “Accept: application/xml” http://localhost:3000/apps/1
Wednesday, June 9, 2010
Mechanizable Web
Wednesday, June 9, 2010
Mechanizable Web
Hyperlinks
Wednesday, June 9, 2010
Mechanizable Web
HyperlinksLink Relations
Wednesday, June 9, 2010
Mechanizable Web
HyperlinksLink Relations
Media Types
Wednesday, June 9, 2010
Mechanizable Web
HyperlinksLink Relations
Media TypesDomain Application Protocol (DAP)
Wednesday, June 9, 2010
Mechanizable Web
HyperlinksLink Relations
Media TypesDomain Application Protocol (DAP)
HATEOAS
Wednesday, June 9, 2010
Mechanizable Web
HyperlinksLink Relations
Media TypesDomain Application Protocol (DAP)
HATEOASHypermedia As The Engine of Application State
Wednesday, June 9, 2010
Protocols
Contract
Wednesday, June 9, 2010
Protocols
Contract
HTTP idioms
Entry-point URIs
Media Types
Protocol
Wednesday, June 9, 2010
Formats Link Relations
Processing Models
Media Type
Schema
Protocols
Contract
HTTP idioms
Entry-point URIs
Media Types
Protocol
Wednesday, June 9, 2010
Improving Restfulie
Wednesday, June 9, 2010
Improving Restfulie
Single interface for representations
Wednesday, June 9, 2010
Improving Restfulie
Single interface for representationsSmart defaults for serialization
Wednesday, June 9, 2010
Improving Restfulie
Single interface for representationsSmart defaults for serialization
XML serialization compatible with Rails
Wednesday, June 9, 2010
Improving Restfulie
Single interface for representationsSmart defaults for serialization
XML serialization compatible with RailsRails 3 compatibility
Wednesday, June 9, 2010
Wednesday, June 9, 2010
One more thing
Wednesday, June 9, 2010
Mikyung
Wednesday, June 9, 2010
Evaluation WorkflowWhen there is a new app
Then move forward to evaluate it
When there is an app being evaluatedAnd the app passes the criteria
Then approve the app
When there is an app being evaluated
And the app doesn't pass the criteriaThen decline the app
Wednesday, June 9, 2010
evaluation_process.rb
require 'restfulie'
class EvaluationProcess < Restfulie::Client::Mikyung::RestProcessModel at "http://localhost:3000/apps/list_new" current_dir File.dirname(__FILE__) follow true
def initialize(*black_list) @black_list = black_list end
def completed?(resource) resource.entries.size == 0 end
def self.run goal = EvaluationProcess.new("Flash", "sex") result = Restfulie::Mikyung.new.achieve(goal).run puts result.response.body endend
Wednesday, June 9, 2010
evaluation_process.rb
require 'restfulie'
class EvaluationProcess < Restfulie::Client::Mikyung::RestProcessModel at "http://localhost:3000/apps/list_new" current_dir File.dirname(__FILE__) follow true
def initialize(*black_list) @black_list = black_list end
def completed?(resource) resource.entries.size == 0 end
def self.run goal = EvaluationProcess.new("Flash", "sex") result = Restfulie::Mikyung.new.achieve(goal).run puts result.response.body endend
Wednesday, June 9, 2010
evaluation_process.rb
require 'restfulie'
class EvaluationProcess < Restfulie::Client::Mikyung::RestProcessModel at "http://localhost:3000/apps/list_new" current_dir File.dirname(__FILE__) follow true
def initialize(*black_list) @black_list = black_list end
def completed?(resource) resource.entries.size == 0 end
def self.run goal = EvaluationProcess.new("Flash", "sex") result = Restfulie::Mikyung.new.achieve(goal).run puts result.response.body endend
Wednesday, June 9, 2010
evaluation_process.rb
require 'restfulie'
class EvaluationProcess < Restfulie::Client::Mikyung::RestProcessModel at "http://localhost:3000/apps/list_new" current_dir File.dirname(__FILE__) follow true
def initialize(*black_list) @black_list = black_list end
def completed?(resource) resource.entries.size == 0 end
def self.run goal = EvaluationProcess.new("Flash", "sex") result = Restfulie::Mikyung.new.achieve(goal).run puts result.response.body endend
Wednesday, June 9, 2010
steps/evaluation_process.rb
def is_valid?(app) result = true @black_list.each do |word| if app.description =~ /#{word}/ result = false end end resultend
Then "move forward to evaluate it" do |resource| @app = @app.links.evaluate.follow.post!("") resourceend
When "the app passes the criteria" do |resource| is_valid?(@app)end
Wednesday, June 9, 2010
steps/evaluation_process.rb
def is_valid?(app) result = true @black_list.each do |word| if app.description =~ /#{word}/ result = false end end resultend
Then "move forward to evaluate it" do |resource| @app = @app.links.evaluate.follow.post!("") resourceend
When "the app passes the criteria" do |resource| is_valid?(@app)end
Wednesday, June 9, 2010
scenarios/evaluation_process.scenario
When there is a new appThen move forward to evaluate it
When there is an app being evaluatedAnd the app passes the criteriaThen approve the app
When there is an app being evaluatedAnd the app doesnt pass the criteriaThen decline the app
Wednesday, June 9, 2010
scenarios/evaluation_process.scenario
When there is a new appThen move forward to evaluate it
When there is an app being evaluatedAnd the app passes the criteriaThen approve the app
When there is an app being evaluatedAnd the app doesnt pass the criteriaThen decline the app
This is Ruby Code!
Wednesday, June 9, 2010
EvaluationProcess.run
http://bit.ly/railsconf2010-restfulie
Wednesday, June 9, 2010
Adaptable Client
Wednesday, June 9, 2010
Adaptable Client
Goal Oriented
Wednesday, June 9, 2010
Adaptable Client
Goal OrientedPattern Matching
Wednesday, June 9, 2010
Adaptable Client
Goal OrientedPattern Matching
Can adapt to some changes
Wednesday, June 9, 2010
Richardson Restful ModelRichardson Restful Model
Level 3 Hypermedia
Level 2 HTTP
Level 1 URI
Wednesday, June 9, 2010
Caelum Restful ModelCaelum Restful Model
Level 5 Code on Demand
Level 4 Adaptable Clients
Level 3 Hypermedia
Level 2 HTTP
Level 1 URI
Wednesday, June 9, 2010
We’re not done yet!
Wednesday, June 9, 2010
Wednesday, June 9, 2010
Thank you!@AkitaOnRails
http://bit.ly/railsconf2010-restfulie
Wednesday, June 9, 2010