Blog ID-INFO
Servizi web su IBM i
Probabilmente avete sentito parlare di servizi web, ma cosa sono esattamente?
Se consultate il vostro motore di ricerca preferito, imparerete che un servizio web è un protocollo di interfaccia che consente a due applicazioni di parlare tra loro. Si basano su tecnologie web per consentire a due applicazioni, che possono essere completamente diverse, di scambiare informazioni.
Di conseguenza, i servizi Web sono spesso utilizzati in ambienti distribuiti, dove molte applicazioni eterogenee devono comunicare tra loro. Inoltre, questi strumenti riprendono i principi dell’architettura orientata ai servizi (SOA), che stanno diventando sempre più comuni nei nostri sistemi informativi e che ci permettono di essere molto più flessibili in termini di soluzioni che possiamo fornire.
Gli attuali servizi Web si basano sull’Hypertext Transfer Protocol (HTPP) per la trasmissione delle informazioni. L’utilizzo di questo standard ha l’enorme vantaggio di evitare un gran numero di problemi di connettività tra le nostre due applicazioni.
I servizi Web si basano su scambi client/server. In pratica, l’applicazione che fornisce il servizio (spesso definita “exposing”) è in ascolto di tutte le richieste fatte dai clienti. La richiesta viene interpretata dal server, elaborata e quindi la risposta viene inviata all’applicazione client in una forma che il client può comprendere.
Esistono due famiglie principali di servizi web:
- Servizi web SOAP: protocollo semplice di accesso agli oggetti
- Servizi web REST: trasferimento di stato rappresentativo
I primi si basano sull’omonimo protocollo. Si tratta di un sistema che esiste da molto tempo: la versione iniziale definita da Microsoft e iBM risale a 23 anni fa, per poi diventare uno standard in seguito a una raccomandazione del W3C. Il protocollo si basa interamente sul linguaggio XML per descrivere formalmente gli scambi tra client e server. Questo formalismo (tramite documenti XML chiamati WSDL) ha il vantaggio di fornire una documentazione implicita quando si utilizza questo tipo di servizio. Purtroppo, la famiglia soffre di alcuni inconvenienti: il linguaggio XML è particolarmente prolisso, quindi l’utilizzo di questo tipo di servizio web può diventare rapidamente complicato. D’altra parte, il formalismo implica che i client e il server siano fortemente accoppiati, il che, in un approccio SOA in cui siamo sempre alla ricerca di una maggiore flessibilità, non è necessariamente auspicabile.
Questi inconvenienti hanno portato alla nascita della famiglia di servizi web REST. Si basano sui concetti architettonici utilizzati nel web per manipolare risorse remote in forma di testo. A differenza dei servizi web SOAP, la famiglia dei servizi web REST non si limita al formato XML per lo scambio di informazioni tra applicazioni client/server: formati come JSON sono ora comunemente utilizzati. Per manipolare risorse remote, questi servizi web utilizzano i metodi http : POST, GET, PUT, DELETE, ecc. che riprendono il modello di sviluppo CRUD, il che spiega perché questi servizi web sono spesso utilizzati per costruire API (Application Programming Interface) complete per interagire con gli elementi di un’applicazione.
Ma che dire del nostro IBM i? Può anch’essa inserirsi in questi ambienti distribuiti?
Permettetemi di rassicurarvi subito: la nostra piattaforma preferita dispone di una vasta gamma di strumenti per esporre o consumare servizi web. Come molte altre piattaforme, possiamo implementare questi servizi in vari modi e metterli a disposizione dei nostri clienti.
Per illustrare il nostro punto di vista, prendiamo un’applicazione esistente sviluppata in RPGIV.
Per farlo, iniziamo a creare un ambiente con alcune tabelle e dati. Fortunatamente, IBM ci ha fornito una stored procedure SQL di una sola riga per questo scopo:
CHIAMARE QSYS.CREATE_SQL_SAMPLE(‘RHDB’); |
Apriamo quindi il nostro strumento di esecuzione di script SQL in ACS e iniziamo.
Come si può intuire dal nome della raccolta creata, lavoreremo con i dati delle risorse umane.
Una rapida occhiata al database explorer mostra le tabelle che sono state create.
Esaminiamo la tabella EMPLOYEE e scriviamo un piccolo programma per recuperare le informazioni su un dipendente.
Supponiamo di avere un programma di servizio che estrae informazioni su un dipendente.
/if not defined(IMPORT_PROTOTYPES)
ctl-opt option ( *nodebugio : *srcstmt )
debug
nomain
pgminfo
(
*PCML
:
*MODULE
);
* Parametres SQL.
exec sql
set option commit
=
*none,
closqlcsr
=
*endmod
;
*======================================================================= *
* *
* ATTENTION : *
* *
* ---------------------------------------------------------------------- *
* FONCTION : Module RH. *
* DESCRIPTION : Manipulation donénes du personnel. *
* *
* Creation ... : 25/10/2021 par L. KIEFFER (Notos-Id Info) *
* ---------------------------------------------------------------------- *
* Modification : *
* JJ/MM/AAAA - XXXXXX XXXXXXX - XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. *
* * * ---------------------------------------------------------------------- *
/endif
*----------------------------------------------------------------------
* Prototype verification sous systeme.
* ---------------------------------------------------------------------
// Information employé.
dcl-ds MODULERH_employe template qualified;
prenom varchar(12);
nom varchar(15);
service varchar(36);
end-ds;
// Recherche d'un employé.
dcl-pr MODULERH_rchEmp;
iNumEmp char( 6 ) const;
oInfEmp likeds ( MODULERH_employe );
oErrHTTP int(5);
oErrMsg varchar(40);
end-pr
;
* Fin des elements exportes.
/if defined(IMPORT_PROTOTYPES)
/eof
/endif
*----------------------------------------------------------------------
* Declarations globales
* ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Recherche d'employé.
// ---------------------------------------------------------------------
dcl-proc MODULERH_rchEmp export;
dcl-pi *n;
iNumEmp char( 6 ) const;
oInfEmp likeds ( MODULERH_employe );
oErrHTTP int(5);
oErrMsg varchar(40);
end-pi
;
// Recherche de l'employé.
exec sql
Select FIRSTNME, LASTNAME, DEPTNAME
into :oInfEmp.prenom, :oInfEmp.nom, :oInfEmp.service
From EMPLOYEE
Join DEPARTMENT on DEPTNO = WORKDEPT
Where EMPNO = :iNumEmp;
if sqlCode < 0;
oErrHTTP = 500;
oErrMsg = 'Erreur recherche de l''employé.';
return;
endif;
if sqlCode = 100;
oErrHTTP = 404;
oErrMsg = 'Employé inconnu.';
return;
endif;
// Tout s'est bien passé.
oErrHTTP = 200;
oErrMsg = *blanks;
return;
end-proc;
Notate le istruzioni evidenziate, su cui torneremo più avanti quando spiegheremo il nostro servizio web.
Per continuare, avremo bisogno di un server di servizi web su cui ospitare i nostri servizi. Fortunatamente per noi, IBM ne fornisce uno su IBM i: IWS (Integrated Web Services server).
Per accedervi, utilizzare il seguente URL: http: //mon_ibm_i:2001/HTTPAdmin
Dove my_ibm_i è l’indirizzo IP della partizione o il suo nome DNS.
AVVERTENZA : se la pagina non viene visualizzata, è probabile che l’applicazione di amministrazione web non sia stata avviata correttamente. Eseguire il seguente comando sulla riga di comando del 5250:
STRTCPSVR SERVER(*HTTP) HTTPSVR(*ADMIN) |
Identificarsi utilizzando un profilo con diritti *IOSYSCFG.
Nella nuova pagina visualizzata, fate clic sul collegamento “Create Web Services Server” e lasciatevi guidare dalla procedura guidata.
Assegnate al vostro server il nome che desiderate. Per impostazione predefinita, verrà creata un’istanza di Apache.
Selezionare le porte utilizzate dal server.
È possibile personalizzare il lavoro del server fornendogli un jobd specifico.
È inoltre possibile scegliere il profilo utente utilizzato dal lavoro del server. Ricordate di definirlo chiaramente. Una buona idea è quella di impostare questo profilo sul profilo del proprietario del database che si intende manipolare. Si noti che se si sceglie l’utente predefinito QWSERVICE, è necessario assegnargli una password.
Infine, confermare la creazione del server facendo clic sul pulsante “Fine”.
Ora che abbiamo un server, parliamo del nostro primo servizio. A tal fine, selezionare il server creato in precedenza e fare clic sul collegamento “Manage Deployed Service”.
Fare clic sul pulsante “Gestisci servizio distribuito”. Quindi fare clic sul pulsante “Deploy”.
La prima pagina della procedura guidata consente di selezionare l’eseguibile che implementa il servizio. Dalla V7.3, è possibile utilizzare anche il linguaggio sql per implementare il servizio.
Per le implementazioni RPG IV, è possibile selezionare solo i componenti eseguibili (programmi e programmi di servizio). Nel nostro caso, scegliamo il programma di assistenza MODULERH.
La schermata successiva ci permetterà di scegliere il nome della risorsa. Nel nostro caso, lo chiameremo “employes” perché stiamo manipolando i dati dei dipendenti.
La pagina seguente consente di limitare l’accesso al servizio web a una porta sicura (tramite SSL). Poiché non abbiamo messo in sicurezza il nostro server http, rispondiamo “No”.
Possiamo anche richiedere l’autenticazione per questo servizio web.
In questo caso, è disponibile solo l’autenticazione “di base”. In questo caso, il cliente dovrà fornire un utente e una password validi sul sistema nell’intestazione http “Authorization”.
Il passo successivo, nel caso di programmi di servizio, consente di selezionare la procedura esportata che implementa il servizio (in questo caso modulerh_rchemp).
L’assistente chiederà quindi come comunicare al cliente che il servizio è stato eseguito come previsto o con un errore. Qui è possibile modificare i codici di ritorno e i messaggi di errore predefiniti.
La pagina successiva è la più importante. Descrive come i clienti accederanno al vostro servizio.
Possiamo definire :
- Il verbo http utilizzato (in questo caso GET)
- Il modello di url utilizzato per l’accesso
Questo ci permette di definire la posizione dei nostri parametri quando vengono forniti direttamente nell’URL. La sintassi da utilizzare è: /{nom_parametre}
Si noti che è possibile aggiungere alla sintassi anche un’espressione regolare per verificare la validità del parametro inserito (qui \d+ per una stringa numerica di almeno una cifra).
- Una variabile di output utilizzata per restituire il codice http (deve essere definita come un numero intero nell’RPG che implementa il servizio).
- Una variabile di output alfanumerica che sostituisce il messaggio di errore predefinito.
- I tipi di dati accettati come input (*Tutti corrisponde a tutti i tipi gestiti: xml, json, dati dei moduli, ecc. => in questo caso, il client deve specificare quale tipo di informazione sta fornendo in modo che il server la comprenda).
- Tipi di dati restituiti: lo strumento può restituire dati in formato xml o json. Anche in questo caso, se il server è in grado di fornire entrambi, il client dovrà specificare quale preferisce.
- Come vengono presentati i dati di ingresso e di uscita: incapsulati o con nome.
Infine, questa schermata consente di indicare da dove verranno recuperati i parametri di input. Nel nostro caso, l’url utilizza l’identificatore num (ricordate che è quello definito nel modello url).
La schermata successiva consente di definire un utente specifico per l’esecuzione del servizio web. Il profilo generale del server deve avere accesso a questo profilo specifico di servizio web.
La schermata successiva serve a definire le librerie da aggiungere all’ambiente di runtime.
La penultima schermata consente di configurare gli elementi da passare al programma che implementa il servizio.
L’ultima schermata riassume le informazioni inserite. Fare clic sul pulsante “Fine” per distribuire e avviare il servizio Web.
Ma come si fa a testare il nostro famoso servizio web?
Il servizio web utilizza il verbo GET, quindi un semplice browser ci permetterà di testarlo.
Per i casi più complessi, è possibile rivolgersi a strumenti più completi come :
- CURL (se non si hanno problemi con le righe di comando): consente di configurare completamente la richiesta (autenticazione, intestazioni http, ecc.).
- PostMan: strumento grafico altrettanto completo di CURL.
Un rapido esempio utilizzando PostMan: aggiungiamo un’intestazione http che indica che vogliamo solo JSON per la risposta (ricordiamo che il nostro servizio web può fornire xml o json).
Ecco fatto, la ‘R’ della nostra API CRUD è ora al suo posto, non resta che creare le altre procedure che implementano le funzioni mancanti. Non dimenticate l’importanza dei verbi http quando impostate tutto questo:
C => POST
R => LETTURA
U => PUT
E D => DELETE.
Spero che questo post abbia chiarito un po’ l’argomento. Vi aspettiamo la prossima volta, quando saremo in grado di proiettarci nei panni del cliente e non in quelli del server.
Avete domande sui servizi web o sulla vostra piattaforma IBM i? Allora contattateci al numero 01 88 32 12 34 o tramite il modulo di contatto.