Ruby

IV parte: Rails... non solo Web Servicesdi

In questo articolo ci occupiamo principalmente delle fasi necessarie alla generazione e fruizione di Web Services in Rails. Faremo ricorso a AWS, Action Web Services e alla libreria SOAP::WSDLDriverFactory. Cerchiamo di arricchire con preziose informazioni le varie fasi del processo.

Introduzione

Non ci siamo ancora occupati (ma ce ne occuperemo nei prossimi articoli) del classico front-end Web basato su pagine HTML, eppure ci immergiamo direttamente nel mondo dei Web Services.
In un contesto in cui le tecnologie di integrazione costituiscono una necessità  continua, abbiamo dato preferenza a tale aspetto e i Web Services sono, senza dubbio, la tecnologia di riferimento per l‘integrazione di sistemi eterogenei.
In luogo degli strumenti a riga di comando finora adoperati nei precedenti articoli, utilizzeremo RadRails come IDE di sviluppo.
Andremo a creare due applicazioni, una per descrivere i passi necessari alla realizzazione di un Web Service da mettere a disposizione per essere fruito, l‘altra per consumare un servizio disponibile. Non trascureremo la fase di test del servizio.
Nell‘effettuare queste operazioni cercheremo di toccare vari aspetti, tutti pragmaticamente interessanti per lo sviluppatore.


La prima applicazione

Iniziamo subito con la fase operativa. Apriamo RadRails (vedi Ruby II per i riferimenti) e creiamo il progetto Rails MokabyteWS. Con un classico File -> New -> Rails Project otteniamo il wizard per la creazione di un progetto Rails.

Figura 1 - Creazione di un progetto con RadRails

Inseriamo il nome del progetto (MokabyteWS nel nostro caso) e, lasciando le impostazioni di default "Generate Rails Application Skeleton" e "Create a Web Brick Server", clicchiamo su ‘Finish‘. La struttura del progetto, a meno di imprevedibili (!!!) errori, risulterà  creata.
Come selezionato con il check avremo a disposizione anche un server sul quale far girare le nostre applicazioni.

Figura 2 - Server WebBrick disponibile per il progetto

A questo punto utilizziamo la base dati utilizzata nell‘articolo precedente (RubyIII) che contiene giusto la nostra tabella "countries". Ã? nostra intenzione consentire la fruizione del contenuto della tabella via Web Services.
Questo il contenuto dello script.


  CREATE TABLE `countries` (
    `id` int(11) NOT NULL auto_increment,
   `name` varchar(128) collate utf8_bin NOT NULL,
   `continent` enum(‘Asia‘,‘Europe‘,‘Africa‘,‘Oceania‘,‘America‘) collate
   utf8_bin NOT NULL,
   PRIMARY KEY  (`id`)
  )

Facciamoci puntare l‘applicazione appena creata (vedi Ruby III parte per i dettagli sulla configurazione... questo solo se non leggi tutti gli articoli su Ruby...).
In particolare ci riferiamo al file create.sql, presente nella cartella db, dove è contenuto lo script di creazione del database e al file database.yml dove ci sono i puntamenti veri e propri dei tre ambienti (sviluppo, test, produzione).
Impostati i parametri delle connessioni al database la view ‘data navigator‘ di RadRails ci consente di effettuare il browsing delle tabelle del database e, in un contesto in cui l‘ORM utilizzato (ActiveRecord) usa un mapping implicito dei campi delle tabelle, questo risulta essere di fondamentale importanza (per non impazzire con i nomi dei campi!!!).
A questo punto passiamo alla creazione del nostro controller. A differenza dell‘articolo precedente non ricorriamo all‘utilizzo di una "scaffold application" ma provvediamo puntualmente alla creazione di ogni componente dell‘applicazione di cui abbiamo bisogno ricorrendo a qualche piccolo intervento in termini di codice mancante al completamento dell‘applicazione (situazione abituale in contesto in cui è il cliente che decide i requisiti funzionali del progetto).
Creiamo il nostro model facendo il mapping della tabella ‘Countries‘. Utilizzando RadRails abbiamo a disposizione, per far questo, una ‘view Generators‘

Figura 3 - Creazione del model con il generator di RadRails

Scegliamo ‘model‘ come primo parametro e impostiamo il nome della tabella come ulteriore parametro. Clicchiamo su ‘Go‘ e attendiamo il generatore che faccia il proprio dovere.
Abbiamo cosଠottenuto il file countries.rb che per il solo fatto di contenere una classe che estende ActiveRecord::Base mappa la tabella con il nome corripondente (di default Rails prende il nome come riferimento tra model e tabella occupandosi lui di fare il plurale nel nome delle tabelle) e una serie di file che costituiscono lo skeleton per le operazioni di test.
Ã? nostra intenzione mettere a disposizione un web service per fruire delle informazioni contenute nella tabella ‘Countries‘. Ricorriamo all‘utilizzo del ‘generator‘ con il parametro ‘web_service‘. Questo consentirà  di generare il controller e la struttura necessaria alla fruizione del web service (con la medesima signature).

Figura 4 - Creazione del web service con il generator  di RadRails.

Notiamo che sono stati creati una serie di files tra i quali:

{rails-project-root}appapiscountry_api.rb
{rails-project-root}appcontrollercountry_controller.rb

Nel primo sono contenute le signature dei metodi, nel secondo le implementazioni dei servizi che saranno resi disponibili via web services. Concentriamoci sul metodo ‘find_all_countries‘. Apriamo country_api.rb e specifichiamo la signature del nostro servizio. Attualmente il contenuto del file è il seguente skeleton:

 class CountryApi < ActionWebService::API::Base
  api_method :find_all_countries
 end

Lo integriamo in modo tale che diventi:

 class CountryApi < ActionWebService::API::Base
  api_method :find_all_countries,
   :returns => [[:string]]
 end

A questo punto il metodo ritornerà  un array di ‘string‘. Ovviamente ‘:returns‘ definisce il ritorno del metodo. In questo caso non abbiamo parametri in input, altrimenti avremmo utilizzato la keyword ‘:expects‘ per dichiararli. Editiamo il file country_controller.rb, attualmente solo uno skeleton. Il file diventerà  qualcosa del tipo

 class CountryController < ApplicationController
  wsdl_service_name ‘Country‘
  web_service_api CountryApi
  web_service_scaffold :invoke
  def find_all_countries
   Country.find(:all).map { |country| country.name}
  end
 end

Il metodo find_all_countries, che utilizza ActiveRecord per recuperare i dati dalla base dati, restituirà  il nome della nazione.
A questo punto è giunto il momento di predisporre un test del nostro servizio. Editiamo il file {rails-project-root} estfunctionalcountry_api_test.rb. Il generatore ha predisposto quasi tutto il necessario per l‘effettuazione del test. Risulta mancante solo l‘implementazione del metodo. Verifichiamo, a puro scopo didattico, che l‘elemento recuperato è una stringa.

 def test_find_all_countries
  result = invoke :find_all_countries
  assert result[0].is_a?(String)
 end

Per lanciare il test dovremmo aggiungere il contenuto informativo della tabella ‘countries‘ destinato ad essere utlizzato durante l‘esecuzione. Quindi apriamo il file {rails-project-root} estfixturescountries.yml e aggiungiamo la nostra nazione di interesse (operazione già  effettuata in RubyIII).
Facciamo lo start del server ‘MokabyteWSServer‘, attendiamo che sia "started" e lanciamo il nostro test test_list_all presente nel file country_api_test.rb. Per la gestione, utilizziamo gli strumenti messi a disposizione dall‘IDE.

Figura 5 - Eseguiamo il nostro test

Se il risultato dell‘esecuzione è qualcosa del tipo


 Runs 1/1 Errors 0 Failures 0

nessun problema per il nostro Web Service. Notiamo che la ‘view‘ Test::TestUnit è molto comoda e utile per tenere sotto controllo l‘esecuzione e la ripetizione dei test da un unico punto.
Andiamo a vedere il nostro wsdl e ...  anche qualche altra funzionalità  messa a disposizione dal framework. Apriamo il browser e puntiamo all‘indirizzo

http://localhost:3000/Country/service.wsdl

Figura 6 - Il wsdl del servizio

Abbiamo il wsdl per tutte le operazioni di condivisione di cui potremmo aver bisogno. Ora puntiamo a

http://localhost:3000/Country/invoke.

Figura 7 - L‘unico servizio che abbiamo reso disponibile

Abbiamo l‘elenco dei metodi resi disponibili nel nostro servizio.
Clicchiamo su FindAllCountries(), otteniamo una pagina in cui possiamo scegliere il protocollo (SOAP o XML-RPC). Scegliendo SOAP otteniamo in visualizzazione i return value (il contenuto del campo name della tabella countries), l‘XML di richiesta e quello in risposta.

Figura 8 - Invocazione del servizio e risultati dell‘invocazione

Niente di più semplice. Siamo pronti per esporre i nostri servizi.

Consumiamo i servizi di un Web Service

Passiamo alla seconda applicazione. Innanzitutto occupiamoci di fruire i servizi del servizio appena messo a disposizione. Sembrerebbe che AWS lasci un pò a desiderare in ambito relativo al consumo di Web Service (in effetti a noi non ha funzionato correttamente) e quindi abbiamo optato per la libreria SOAP::WSDLDriverFactory presente nel pacchetto base.
Creiamo un progetto Ruby e lo chiamiamo ‘MokabyteWSClient‘ con il solito iter File -> New -> Ruby Project. Per la fruizione abbiamo bisogno di due file. Il file countries_api.rb (lo stesso del progetto precedente) dove sono contenute le signature dei metodi e il wsclient.rb con le seguenti informazioni.

 require ‘soap/wsdlDriver‘
 require ‘cgi‘
 endpoint = ‘http://localhost:3000/country/service.wsdl‘
 soap = SOAP::WSDLDriverFactory.new(endpoint).create_rpc_driver
 countries = soap.FindAllCountries

Il significato del codice risulta essere piuttosto intuitivo. Proviamo a lanciare il nostro wsclient.rb, magari mettendo un punto di debug e facendo un ‘inspect‘ della variabile ‘countries‘.

Figura 9 - Inspect della variabile countries dopo l‘invocazione del web service remoto

Il risultato dovrebbe essere qualcosa di molto simile a quanto sopra riportato.

Conclusioni

Basando la nostra procedura di sviluppo su RadRails, ci siamo occupati di generare model, controller, web services e abbiamo poi provveduto a effettuare le mancanti operazioni di ‘knitting‘ necessarie all‘applicazione per funzionare come richiesto. Quindi siamo passati alla fruizione del web service.
Abbiamo testato il tutto con estrema facilità  e tenendo tutto (test, debug, database) sotto controllo dall‘ l‘IDE. Un IDE che si sta evolvendo molto rapidamente. A testimonianza del grosso fermento che si sta muovendo intorno al mondo Ruby/RoR è notizia recente che Aptana, l‘IDE, basato su Eclipse (prevalentemente orientata a sviluppi Ajax) ha inglobato le features che erano di RadRails. Qualche altro vendor di rilievo, tra i quali Borland (http://www.codegear.com/products/rubyide), comincia a puntare su Ruby on Rails.
Questo fermendo intorno al mondo RoR ci fa sicuramente piacere e ci spinge a continuare in questa direzione.


Riferimenti

[1] Dave Thomas, "Programming Ruby. The Pragmatic Programmer‘s Guide", Pragmatic Bookshelf, 2004
http://www.pragmaticprogrammer.com

[2] Dave Thomas, "Agile Software Development with Rails. The Pragmatic Programmer‘s Guide", Pragmatic Bookshelf, 2005
http://www.pragmaticprogrammer.com

[3] RadRails (redirect al sito di Aptana)
http://www.radrails.org

[4] Aptana IDE + Rails
http://aptana.com/download_rails_rdt.php

[5] Code Gear
http://www.codegear.com/products/rubyide

[6] Calling a .NET Web Service From Rails
http://webgambit.com/archive/2007/01/10/calling-a-net-web-service-from-rails-original.aspx

Condividi

Pubblicato nel numero
119 giugno 2007
Laureato in Scienze Statistiche e particolarmente attento alle novità che lo circondano, dal 1998 lavora nel settore dell‘IT. Prevalentemente coinvolto in progetti legati a Java, da un paio d‘anni è interessato al mondo Open Source. Dopo aver accumulato una notevole esperienza presso vari clienti e con vari ruoli (da programmatore…
Articoli nella stessa serie
  • Ruby
    I parte: introduzione al linguaggio
  • Ruby
    II parte: approfondiamo alcuni aspetti del linguaggio Ruby
  • Ruby
    III parte: Iniziamo a percorrere i binari di Rails
  • Ruby
    V parte: Ruby on Rails e Web 2.0
Ti potrebbe interessare anche