2009-04-14 10 views
54

Mi piacerebbe scrivere un'applicazione Ruby on Rails che consumi un'API di servizio Web RESTful esegue una logica sul risultato e quindi visualizza tali dati sulla mia vista. Per esempio, diciamo che volevo scrivere un programma che facesse una ricerca su search.twitter.com. Utilizzando rubino puro potrei creare il seguente metodo:Qual è il corretto "Modo Rails" per consumare un servizio web RESTful su un altro dominio?

def run(search_term='', last_id=0) 
    @results = [] 
    url = URI.parse("http://search.twitter.com") 
    res = Net::HTTP.start(url.host, url.port) do |http| 
    http.get("/search.json?q=#{search_term}&since_id=#{last_id.to_s}") 
    end 
    @results = JSON.parse res.body 
end 

Mi verrebbe da solo cadere quel metodo nel mio controller Rails come un metodo privato, ma una parte di me pensa che ci sia una migliore, più "Rails" modo per farlo. Esiste un approccio alle migliori pratiche o è davvero il modo migliore?

risposta

51

esiste un plugin/gioiello chiamato HTTParty che ho usato per diversi progetti.

http://johnnunemaker.com/httparty/

HTTParty consente di consumare facilmente qualsiasi servizio web e analizza i risultati in un hash per voi. Quindi è possibile utilizzare l'hash stesso o creare un'istanza di una o più istanze del modello con i risultati. L'ho fatto in entrambi i modi.

Per l'esempio di Twitter, il codice sarebbe simile a questa:

class Twitter 
    include HTTParty 
    base_uri 'twitter.com' 

    def initialize(u, p) 
    @auth = {:username => u, :password => p} 
    end 

    # which can be :friends, :user or :public 
    # options[:query] can be things like since, since_id, count, etc. 
    def timeline(which=:friends, options={}) 
    options.merge!({:basic_auth => @auth}) 
    self.class.get("/statuses/#{which}_timeline.json", options) 
    end 

    def post(text) 
    options = { :query => {:status => text}, :basic_auth => @auth } 
    self.class.post('/statuses/update.json', options) 
    end 
end 

# usage examples. 
twitter = Twitter.new('username', 'password') 
twitter.post("It's an HTTParty and everyone is invited!") 
twitter.timeline(:friends, :query => {:since_id => 868482746}) 
twitter.timeline(:friends, :query => 'since_id=868482746') 

Come ultimo punto, è possibile utilizzare il vostro codice di cui sopra anche, ma sicuramente includere il codice in un modello in contrapposizione ad un controller.

+0

Amo questa gemma. Ciò rende i servizi Web che consumano davvero chiari. Una domanda che ho ancora è se Rails abbia già qualcosa di costruito per farlo? Sembra che questa sia una cosa abbastanza comune da provare a fare che avrebbero un modo per farlo. –

+0

Inoltre, perdona la noobiosità del mio Rails :), come potrei installarlo come modello. Ho usato solo modelli per l'accesso al database usando ActiveRecord. –

+7

Non c'è nulla di integrato nel core delle rotaie. Un modello è solo una classe: basta creare una classe nella directory dei modelli e non ereditare da ActiveRecord: classe Base. Non avrai nessuna delle qualità di AR incluse, ma questo è uno schema piuttosto comune per il consumo di servizi web all'interno di un'app per rails –

11

se il servizio Web RESTful remoto è stato anche creato con Ruby on Rails, ActiveResource è la strada da percorrere.

+0

non riesco a quel presupposto come desidero estrarre dati da molti siti web diversi in cui avrei alcuna idea di ciò che il quadro sottostante sarebbe. Ma guarderò ActiveResource per le cose che so essere Rails. Grazie! –

+4

In realtà, il servizio RESTful remoto non deve essere creato utilizzando Rails per ActiveResource per funzionare. L'implementazione sottostante non ha importanza. – WattsInABox

+0

Questo è sicuramente il modo preferito da Rails per consumare risorse RESTful. Mantiene il codice pulito e conforme a MVC. –

2

In risposta al tuo esempio Twitter, c'è un Twitter Gem che avrebbe aiutato per automatizzare questo per voi.

23

Restclient è davvero una bella soluzione a questo problema.

require 'rest_client' 
RestClient.get 'http://example.com/resource' 
RestClient.get 'http://example.com/resource', {:params => {:id => 50, 'foo' => 'bar'}} 

Dal readme.

+1

Concordo pienamente con il client rest. È davvero un ottimo framework per gestire tutte le chiamate API. – mhenrixon

+0

Roba eccellente. Venendo da iOS, questo è esattamente quello che volevo. – samvermette

+1

Preferisco fortemente RestClient a HTTParty. Mi sento più a terra, meno magico per me. YMMV – Duke

Problemi correlati