ActiveResource & REST

121
REST & ActiveResource Matthijs Langenberg

description

Matthijs Langenberg's slide's of his presentation at the RubyenRails 2007 conf in Amsterdam.

Transcript of ActiveResource & REST

Page 1: ActiveResource & REST

REST & ActiveResourceMatthijs Langenberg

Page 2: ActiveResource & REST

Webservices

Page 3: ActiveResource & REST
Page 4: ActiveResource & REST
Page 5: ActiveResource & REST
Page 6: ActiveResource & REST
Page 7: ActiveResource & REST
Page 8: ActiveResource & REST
Page 9: ActiveResource & REST

Wat zijn webservices

Page 10: ActiveResource & REST

”The W3C defines a Web Service as a software system designed to support interoperable machine to machine interaction over a network.”

-- Wikipedia

Page 11: ActiveResource & REST

Bevorder ‘machine to machine interaction’

Page 12: ActiveResource & REST

HTML is moeilijk te parsen

Page 13: ActiveResource & REST

Geef iets anders terug

XML?

Page 14: ActiveResource & REST

Just Another View

Page 15: ActiveResource & REST

respond_to

Page 16: ActiveResource & REST

class ArticlesController < ApplicationController def show @article = Article.find(params[:id]) respond_to do |format| format.html format.xml { render :xml => @article } end endend

Page 17: ActiveResource & REST

Soorten Webservices

• Remote procedure calls (RPC)

• Service-oriented architecture (SOA)

• Representational state transfer (REST)

Page 18: ActiveResource & REST

Rails votes REST

Page 19: ActiveResource & REST

Rails votes REST

BIG TIME!

Page 20: ActiveResource & REST

Wat is REST?

Page 21: ActiveResource & REST
Page 22: ActiveResource & REST
Page 23: ActiveResource & REST
Page 24: ActiveResource & REST

REpresentional State Transfer

Page 25: ActiveResource & REST

HTTP’s: “convention over configuration”

Page 26: ActiveResource & REST

Schreef geen vervanging voor iets wat HTTP je gratis geeft

Page 27: ActiveResource & REST

HTTP Abuse

Wat is er mis met dit request?

GET http://myblog.com/articles/destroy/1

Page 28: ActiveResource & REST

HTTP Abuse

Wat is er mis met dit request?

GET http://myblog.com/articles/destroy/1

Conflict

Page 29: ActiveResource & REST

HTTP Abuse

Wat is er mis met dit request?

GET http://myblog.com/articles/destroy/1

Conflict

• Actie staat in URL• Uitgevoerd actie is in conflict met HTTP methode

Page 30: ActiveResource & REST

The REST-way

DELETE http://myblog.com/articles/1

Page 31: ActiveResource & REST

URI’s

Page 32: ActiveResource & REST

URI’s

GET /articles/create

GET /articles/show/1

GET /articles/update/1

GET /articles/destroy/1

Page 33: ActiveResource & REST

URI’s

GET /articles/create

GET /articles/show/1

GET /articles/update/1

GET /articles/destroy/1

Page 34: ActiveResource & REST

Mapping

Page 35: ActiveResource & REST

HTTP

GET

POST

PUT

DELETE

Mapping

Page 36: ActiveResource & REST

HTTP

GET

POST

PUT

DELETE

Controller

SHOW

CREATE

UPDATE

DESTROY

Mapping

Page 37: ActiveResource & REST

Resourceful URI’s

Page 38: ActiveResource & REST

GET /articles

POST /articles/create

GET /articles/show/1

POST /articles/update/1

GET /articles/destroy/1

Resourceful URI’s

Page 39: ActiveResource & REST

GET /articles

POST /articles/create

GET /articles/show/1

POST /articles/update/1

GET /articles/destroy/1

Resourceful URI’s

➡ GET /articles

➡ POST /articles

➡ GET /articles/1

➡ PUT /articles/1

➡ DELETE /articles/1

Page 40: ActiveResource & REST

Gratis named routes

Page 41: ActiveResource & REST
Page 42: ActiveResource & REST

ActionController::Routing::Routes.draw do |map|map.resources :articles do |articles|articles.resources :comments

endend

Page 43: ActiveResource & REST

ActionController::Routing::Routes.draw do |map|map.resources :articles do |articles|articles.resources :comments

endend

Page 44: ActiveResource & REST

articles_urlarticle_urlnew_article_urledit_article_url

article_comments_urlarticle_comment_urlarticle_new_comment_urlarticle_edit_comment_url

ActionController::Routing::Routes.draw do |map|map.resources :articles do |articles|articles.resources :comments

endend

Page 45: ActiveResource & REST

articles_urlarticle_urlnew_article_urledit_article_url

article_comments_urlarticle_comment_urlarticle_new_comment_urlarticle_edit_comment_url

➡ /articles➡ /articles/:id➡ /articles/new➡ /articles/:id/edit

➡ /articles/:article_id/comments➡ /articles/:article_id/comments/:id➡ /articles/:article_id/comments/new➡ /articles/:article_id/comments/:id/edit

ActionController::Routing::Routes.draw do |map|map.resources :articles do |articles|articles.resources :comments

endend

Page 46: ActiveResource & REST
Page 47: ActiveResource & REST

link_to article.title, { :controller => ‘article’, :action => ‘show’, :id => article }

Page 48: ActiveResource & REST

link_to article.title, { :controller => ‘article’, :action => ‘show’, :id => article }

Page 49: ActiveResource & REST

link_to article.title, { :controller => ‘article’, :action => ‘show’, :id => article }

link_to article.title, article_url(article)

Page 50: ActiveResource & REST

link_to article.title, { :controller => ‘article’, :action => ‘show’, :id => article }

link_to article.title, article_url(article)

link_to article.title, article

Page 51: ActiveResource & REST

Wat zou je doen?Je wilt comments aan articles toevoegen,ArticlesController is aanwezig.

Page 52: ActiveResource & REST

Wat zou je doen?Je wilt comments aan articles toevoegen,ArticlesController is aanwezig.

1) Voeg een actie ‘add_comment’ aan ArticlesController toe.(POST /articles/1/add_comment)

Page 53: ActiveResource & REST

Wat zou je doen?Je wilt comments aan articles toevoegen,ArticlesController is aanwezig.

1) Voeg een actie ‘add_comment’ aan ArticlesController toe.(POST /articles/1/add_comment)

2) Maak een CommentsController, met een ‘create’ actie.(POST /comments/create?article_id=1)

Page 54: ActiveResource & REST

Mr. RESTful zegt:

Page 55: ActiveResource & REST

Mr. RESTful zegt:Antwoord 2

Page 56: ActiveResource & REST

Mr. RESTful zegt:Antwoord 2

• Een comment is een een aparte resource

Page 57: ActiveResource & REST

Mr. RESTful zegt:Antwoord 2

• Een comment is een een aparte resource• Er bestaat geen ‘add_comment’ methode in HTTP

Page 58: ActiveResource & REST

Mr. RESTful zegt:Antwoord 2

• Een comment is een een aparte resource• Er bestaat geen ‘add_comment’ methode in HTTP• Er bestaat wel een ‘create’ (POST) methode in HTTP

Page 59: ActiveResource & REST

Geen Namespaces!

• POST /articles/create

• POST /articles/create_comment

• GET /articles/destroy

• GET /articles/destroy_comment

Page 60: ActiveResource & REST

Teveel vrijheid is niet goed

Page 61: ActiveResource & REST

class ArticlesController < ApplicationController def show @article = Article.find(params[:id]) end

def show_rss @article = Article.find(params[:id]) render :rss => @article.to_rss end

def show_atom @article = Article.find(params[:id]) render :atom => @article.to_atom end

def show_xml @article = Article.find(params[:id]) render :xml => @article.to_xml end

def show_ajax @article = Article.find(params[:id]) render :template => show_article.rjs endend

Page 62: ActiveResource & REST

Geen aparte actie voor alternatieve view!

Page 63: ActiveResource & REST

class ArticlesController < ApplicationController def show @article = Article.find(params[:id]) respond_to do |format| format.html format.rss { render :rss => @article.to_rss } format.atom { render :atom => @article.to_atom } format.xml { render :xml => @article.to_xml } format.rjs { render :template => ‘show_article.rjs’ } end endend

Page 64: ActiveResource & REST

Wauw! HTTP method naar controller actie mapping actie klinkt tof!

Page 65: ActiveResource & REST

Maar er zit een adder ...

Page 66: ActiveResource & REST

Maar er zit een adder ...

Page 67: ActiveResource & REST

Browsers ondersteunen PUT en DELETE niet!

Page 68: ActiveResource & REST

Browsers ondersteunen PUT en DELETE niet!

<input name="_method" type="hidden" value="put" />

Page 69: ActiveResource & REST

Gelukkig zijn de helpers ook aangepast. ;-)

Page 70: ActiveResource & REST

HTML_options

• link_to “delete”, article_path(1), :method => ‘delete’

• link_to_remote, “delete”, article_path(1), :method => ‘delete’

• form_tag(member_path(2), :method => :put)

Page 71: ActiveResource & REST

form_forremote_form_for

Bepalen op basis van AR object de method:

form_for(Movie.new):

<form action="/movies" class="new_movie" id="new_movie" method="post">

form_for(Movie.find(:first)):

<form action="/movies/1" class="edit_movie" id="edit_movie_1" method="post">

<input name="_method" type="hidden" value="put" />

Page 72: ActiveResource & REST

Controller Acties

Page 73: ActiveResource & REST

MoviesController#index

Page 74: ActiveResource & REST

MoviesController#index

# GET /movies # GET /movies.xml def index @movies = Movie.find(:all)

respond_to do |format| format.html # index.html.erb format.xml { render :xml => @movies } end end

Page 75: ActiveResource & REST

MoviesController#index

# GET /movies # GET /movies.xml def index @movies = Movie.find(:all)

respond_to do |format| format.html # index.html.erb format.xml { render :xml => @movies } end end

<?xml version="1.0" encoding="UTF-8"?><movies> <movie> <director>Chris Miller</director> <id type="integer">1</id> <rating type="decimal">7.0</rating> <title>Shrek the Third</title> </movie> <movie> <director>Sam Raimi</director> <id type="integer">2</id> <rating type="decimal">6.9</rating> <title>Spider-Man 3</title> </movie> <movie> <director>Juan Carlos Fresnadillo</director> <id type="integer">3</id> <rating type="decimal">7.7</rating> <title>28 Weeks Later</title> </movie></movies>

Page 76: ActiveResource & REST

MoviesController#show

Page 77: ActiveResource & REST

MoviesController#show # GET /movies/1 # GET /movies/1.xml def show @movie = Movie.find(params[:id])

respond_to do |format| format.html # show.html.erb format.xml { render :xml => @movie } end end

Page 78: ActiveResource & REST

MoviesController#show # GET /movies/1 # GET /movies/1.xml def show @movie = Movie.find(params[:id])

respond_to do |format| format.html # show.html.erb format.xml { render :xml => @movie } end end

<?xml version="1.0" encoding="UTF-8"?><movie> <director>Chris Miller</director> <id type="integer">1</id> <rating type="decimal">7.0</rating> <title>Shrek the Third</title></movie>

Page 79: ActiveResource & REST

MoviesController#create

Page 80: ActiveResource & REST

MoviesController#create

# POST /movies # POST /movies.xml def create @movie = Movie.new(params[:movie])

respond_to do |format| if @movie.save flash[:notice] = 'Movie was successfully created.' format.html { redirect_to(@movie) } format.xml { render :xml => @movie,

:status => :created, :location => @movie }

else format.html { render :action => "new" } format.xml { render :xml => @movie.errors, :status => 422 } end end end

Page 81: ActiveResource & REST

MoviesController#create

# POST /movies # POST /movies.xml def create @movie = Movie.new(params[:movie])

respond_to do |format| if @movie.save flash[:notice] = 'Movie was successfully created.' format.html { redirect_to(@movie) } format.xml { render :xml => @movie,

:status => :created, :location => @movie }

else format.html { render :action => "new" } format.xml { render :xml => @movie.errors, :status => 422 } end end end

Status: 201 CreatedLocation: http://localhost:3000/movies/16<?xml version="1.0" encoding="UTF-8"?><movie> <director>Steven Spielbergh</director> <id type="integer">15</id> <rating type="decimal">8.3</rating> <title>Letters from Iwo Jima</title></movie>

Page 82: ActiveResource & REST

MoviesController#create

# POST /movies # POST /movies.xml def create @movie = Movie.new(params[:movie])

respond_to do |format| if @movie.save flash[:notice] = 'Movie was successfully created.' format.html { redirect_to(@movie) } format.xml { render :xml => @movie,

:status => :created, :location => @movie }

else format.html { render :action => "new" } format.xml { render :xml => @movie.errors, :status => 422 } end end end

Status: 422 Unprocessable Entity<?xml version="1.0" encoding="UTF-8"?><errors> <error>Rating can't be blank</error> <error>Director can't be blank</error> <error>Title can't be blank</error></errors>

Status: 201 CreatedLocation: http://localhost:3000/movies/16<?xml version="1.0" encoding="UTF-8"?><movie> <director>Steven Spielbergh</director> <id type="integer">15</id> <rating type="decimal">8.3</rating> <title>Letters from Iwo Jima</title></movie>

Page 83: ActiveResource & REST

MoviesController#update

Page 84: ActiveResource & REST

MoviesController#update

# PUT /movies/1 # PUT /movies/1.xml def update @movie = Movie.find(params[:id])

respond_to do |format| if @movie.update_attributes(params[:movie]) flash[:notice] = 'Movie was successfully updated.' format.html { redirect_to(@movie) } format.xml { head :ok } else format.html { render :action => "edit" } format.xml { render :xml => @movie.errors, :status => 422 } end end end

Page 85: ActiveResource & REST

MoviesController#update

# PUT /movies/1 # PUT /movies/1.xml def update @movie = Movie.find(params[:id])

respond_to do |format| if @movie.update_attributes(params[:movie]) flash[:notice] = 'Movie was successfully updated.' format.html { redirect_to(@movie) } format.xml { head :ok } else format.html { render :action => "edit" } format.xml { render :xml => @movie.errors, :status => 422 } end end end

Status: 200 OK

Page 86: ActiveResource & REST

MoviesController#update

# PUT /movies/1 # PUT /movies/1.xml def update @movie = Movie.find(params[:id])

respond_to do |format| if @movie.update_attributes(params[:movie]) flash[:notice] = 'Movie was successfully updated.' format.html { redirect_to(@movie) } format.xml { head :ok } else format.html { render :action => "edit" } format.xml { render :xml => @movie.errors, :status => 422 } end end end

Status: 422 Unprocessable Entity<?xml version="1.0" encoding="UTF-8"?><errors> <error>Title can't be blank</error></errors>

Status: 200 OK

Page 87: ActiveResource & REST

MoviesController#destroy

Page 88: ActiveResource & REST

MoviesController#destroy

# DELETE /movies/1 # DELETE /movies/1.xml def destroy @movie = Movie.find(params[:id]) @movie.destroy

respond_to do |format| format.html { redirect_to(movies_url) } format.xml { head :ok } end end

Page 89: ActiveResource & REST

MoviesController#destroy

# DELETE /movies/1 # DELETE /movies/1.xml def destroy @movie = Movie.find(params[:id]) @movie.destroy

respond_to do |format| format.html { redirect_to(movies_url) } format.xml { head :ok } end end

Status: 200 OK

Page 90: ActiveResource & REST

Scaffolding

Page 91: ActiveResource & REST

maar er is meer!

Page 92: ActiveResource & REST

ActiveResource

Page 93: ActiveResource & REST

ActiveResource

• Object-oriented REST services

• Transparent met een RESTful service (Rails) werken

• Net als ActiveRecord, maar dan voor REST

Page 94: ActiveResource & REST

Browser

Page 95: ActiveResource & REST

Controller(RESTful)

Browser

GET /movies.html

Page 96: ActiveResource & REST

Controller(RESTful)

ActiveRecord

Browser

GET /movies.html

Movie.find(:all)

Page 97: ActiveResource & REST

Controller(RESTful)

ActiveRecord

Browser

DB

GET /movies.html

Movie.find(:all)

SELECT * FROM MOVIES

Page 98: ActiveResource & REST

Controller(RESTful)

Browser

ActiveRecord

Browser

DB

GET /movies.html

Movie.find(:all)

SELECT * FROM MOVIES

Page 99: ActiveResource & REST

Controller(RESTful)

Browser

ActiveRecord

Browser

Controller

DB

GET /movies.html GET /movies.html

Movie.find(:all)

SELECT * FROM MOVIES

Page 100: ActiveResource & REST

Controller(RESTful)

Browser

ActiveRecord

Browser

Controller

ActiveResource

DB

GET /movies.html

Movie.find(:all)

GET /movies.html

Movie.find(:all)

SELECT * FROM MOVIES

Page 101: ActiveResource & REST

Controller(RESTful)

Browser

ActiveRecord

Browser

Controller

ActiveResource

DB

GET /movies.html

Movie.find(:all)

GET /movies.xml

GET /movies.html

Movie.find(:all)

SELECT * FROM MOVIES

Page 102: ActiveResource & REST

Configuratie

Page 103: ActiveResource & REST

Werken met RESTful webservices(ActiveResource)

Page 104: ActiveResource & REST

Create

Page 105: ActiveResource & REST

Create

Page 106: ActiveResource & REST

Read

Page 107: ActiveResource & REST

Read

Page 108: ActiveResource & REST

Update

Page 109: ActiveResource & REST

Update

Page 110: ActiveResource & REST

Destroy

Page 111: ActiveResource & REST

Destroy

Page 112: ActiveResource & REST

Wat doet ARes?

Page 113: ActiveResource & REST

Wat doet ARes?

• Genereer URL

Page 114: ActiveResource & REST

Wat doet ARes?

• Genereer URL

• Request URL (XML)

Page 115: ActiveResource & REST

Wat doet ARes?

• Genereer URL

• Request URL (XML)

• Verwerk request (XML)

Page 116: ActiveResource & REST

Wat doet ARes?

• Genereer URL

• Request URL (XML)

• Verwerk request (XML)

• Biedt ActiveRecord-like API

Page 117: ActiveResource & REST

Demo

Page 118: ActiveResource & REST

Demo

1) RESTful Rails applicatie (met curl)

Page 119: ActiveResource & REST

Demo

1) RESTful Rails applicatie (met curl)

2) Rails applicatie met ActiveResource

Page 120: ActiveResource & REST

Demo

1) RESTful Rails applicatie (met curl)

2) Rails applicatie met ActiveResource

3) ActiveResource gem

Page 121: ActiveResource & REST

Vragen?

<[email protected]>#rubyenrails at irc.freenode.org