Archive for 15/04/2017

Uniface ed i Web Services, 3.parte – REST

Nella seconda parte abbiamo affrontato i “Web Services” rispondenti alla specifica SOAP, in questa terza parte affrontiamo quelli rispondenti ai criteri REST.

Un “Web Service” REST è un normale componente web in grado di restituire contenuti in un formato testuale utilizzando http(s) come protocollo di trasporto; questo formato testuale NON è precisato nei criteri REST, può essere HTML o XML o JSON o semplice testo. Nei nostri esempi assumeremo che il formato testuale utilizzato sia JSON, che è il formato più comunemente utilizzato.
JSON è l’acronimo di “JavaScript Object Notation”, ed è un formato adatto per lo scambio dei dati in applicazioni client-server. È basato sul linguaggio JavaScript Standard ECMA-262 3ª edizione dicembre 1999, ma ne è indipendente. Fornisce una alternativa ad XML ed è spesso utilizzato in applicazioni web per la serializzazione e trasmissione di informazioni sulla rete.

In Uniface la fruizione (consumo) di servizi REST passa attraverso l’utilizzo del componente UHTTP; tale componente associa in una singola chiamata una accoppiata request/response via http/https. Le operazioni che rende disponibili permettono di attuare diverse funzionalità:
– SEND: invia una request HTTP utilizzando il metodo specificato, come PUT o POST per file upload e GET per file download.
– SET_FLAGS: setta parametri di esecuzione per la successiva operazione SEND determinando come Uniface gestisce la comunicazione http.
– SET_TIMEOUT: stabilisce l’ammontare di tempo debba essere atteso da una request HTTP prima di considerarla completata.
– WRITE_CONTENT: appende un segmento di dati al buffer UHTTP, che verrà utilizzato dall’operazione SEND. Non può essere utilizzata insieme alle operazioni sui file, come  LOAD_FILE_CONTENTS.
– READ_CONTENT: ottiene informazioni aggiuntive sull’ultima request http. Non può essere utilizzata insieme alle operazioni sui file, come DUMP_FILE_CONTENTS.
– LOAD_FILE_CONTENTS:carica un file, o parte di esso, nel body di una request prima di chiamare l’operazione di SEND per inviare il file.
– DUMP_FILE_CONTENTS:crea un file locale leggendo il body di una response che contiene il file, o un suo spezzone.
– GET_INFO: acquisisce informazioni sul body di un messaggio prima o dopo una operazione SEND. Risulta utili quando il body di una request contiene informazioni relative al file corrente, non essendoci nessun altro modo per conoscere la lunghezza o la zona del file richiesta.
– CLOSE_FILE: chiude il file corrente che è stato utilizzato per l’invio a spezzoni del suo contenuto.

Esempi: (Richiedetemi form di esempio GSX_TEST_UHTTP)
– activate uhttp.send(“https://jsonplaceholder.typicode.com/posts”, “GET”, username, password, headers, content, response)
Restituisce TUTTI i post memorizzati
– activate uhttp.send(“https://jsonplaceholder.typicode.com/posts/1”, “GET”, username, password, headers, content, response)
Restituisce il post memorizzato con ID = 1
– activate uhttp.send(“https://jsonplaceholder.typicode.com/posts?userId=1”, “GET”, username, password, headers, content, response)
Restituisce i post memorizzati dall’utente con ID = 1
– activate uhttp.send(“https://jsonplaceholder.typicode.com/posts/1/comments”, “GET”, username, password, headers, content, response)
Restituisce i commenti associati al post con ID = 1
– activate uhttp.send(“https://jsonplaceholder.typicode.com/posts”, “POST”, username, password, headers, “{%%^title: ‘foo’,%%^body: ‘bar’,%%^userId: 1%%^}”, response)
Aggiunge una occorrenza e restituisce l’ID assegnato
– activate uhttp.send(“https://jsonplaceholder.typicode.com/posts/1”, “PUT”, username, password, headers, “{%%^title: ‘foo’,%%^body: ‘bar’,%%^userId: 1%%^}”, response)
Aggiorna l’occorrenza con ID = 1
– activate uhttp.send(“https://jsonplaceholder.typicode.com/posts/1”, “DELETE”, username, password, headers, content, response)
Cancella l’occorrenza con ID = 1

In Uniface la creazione/gestione di uno stream JSON è estremamente facilitata attraverso istruzioni specifiche:
– JSONtoStruct: definisce una variabile di tipo struct a partire da uno stream JSON
– StructToJSON: costruisce uno stream JSON a partire da una variabile di tipo struct
– webload: carica i dati da uno stream JSON su un componente Uniface
– websave /mod | /one: crea uno stream JSON dai dati in a componente Uniface
– uniface.datastore.put(): salva nel browser un documento (insieme di dati in genere in formato JSON) contraddistinti da un ID
– uniface.datastore.get(): recupera dal browser un documento (insieme di dati in genere in formato JSON) passando l’ID corrispondente
– uniface.datastore.remove(): cancella dal browser un documento (insieme di dati in genere in formato JSON) passando l’ID corrispondente
– uniface.getData()
– uniface.setData()

La creazione un web service al fine di fornire dati secondi i criteri REST è molto semplice e passa attraverso lo sviluppo di una DSP; bastano poche linee di codice per:
– leggere eventuali parametri in ingresso dai canali INPUT o PATHINPUT o dall’header del pacchetto ricevuto
– restituire lo stream JSON nel canale OUTPUT
Esempio di codice da inserire nel trigger di “Execute” della DSP:
public web
variables
string vInput  ; Input parameter from URL
string vOutput ; Output content to be returned
endvariables
; — 1 — get input parameter
getitem/id vInput, $webinfo(“PATHINPUT”), “name”
; — 2 — create output based on input
; you can do anything here
vOutput = “Hello %%vInput%%%, I am the output”
; — 3 — fill the output channel
$webinfo(“output”) = vOutput
; And we are done !
return(0)
end
Questa struttura di base va poi adattata a quanto realmente necessario utilizzando le funzioni creazione di stream JSON elencate in precedenza.

La parte più critica dei Web Services REST rimane la totale assenza di una documentazione standard delle interfacce predisposte, qualcosa assimilabile al WSDL dei servizi SOAP; ci sono iniziative a questo riguardo ma non hanno ancora raggiunto una stabilità e riconoscimenti adeguati. Di conseguenza il criterio con il quale i dati vengono scambiati (parametri, tipi di dato trasferiti, formati degli stessi, …) va documentato adeguatamente rispetto alle esigenze identificate. In alcuni casi si constata l’utilizzo di un metodo HTTP specifico (OPTIONS) che elenchi e documenti le chiamate disponibili.

Nella prossima parte parleremo dei criteri con i quali è possibile definire una API mediante i web services, siano essi SOAP o REST.