Lezione 11: Accesso ai RESTful Web Services in Java
1. Lezione 11: Accesso ai
RESTful Web Services in
Java
Corso di Programmazione in Rete
Laurea Magistrale in Ing. Informatica
Università degli Studi di Salerno
1
2. Outline
✦ Struttura di un WS RESTful
✦ Realizzazione di client in Java: le classi
URL e HttpURLConnection
✦ La codifica x-www-form-urlencoded
2
3. Struttura di un WS RESTful
✦ Elementi fondamentali di un Web Service
basato sull’architettura REST:
• Risorse
• Rappresentazioni delle risorse
• Operazioni sulle risorse
3
4. Risorse
✦ Un servizio RESTful gestisce un insieme
di risorse
• Esempio: in un sistema di commercio elettronico
le risorse possono essere i prodotti e gli ordini
✦ Una risorsa può rappresentare una
“collezione” di altre risorse
• Esempio: una risorsa può rappresentare l’insieme
degli ordini effettuati da un determinato utente
4
5. Risorse
✦ Ogni risorsa è identificata attraverso un
URL specifico
• è semplice trasferire l’indirizzo di una risorsa ad
un altra applicazione, creare dei collegamenti tra
risorse, mantenere dei “bookmark” ecc.
✦ Esempio:
• http://mycommerce.com/products
‣ Insieme dei prodotti
• http://mycommerce.com/products/14287
‣ Singolo prodotto
5
6. Rappresentazioni
✦ Le risorse sono entità astratte
caratterizzate da uno stato che può
cambiare nel tempo
• ad esempio, un prodotto ha un nome, una
descrizione, un prezzo, una disponibilità ecc.
✦ Il client e il server comunicano
scambiandosi rappresentazioni dello stato
delle risorse (ecco perché si parla di
REpresentational State Transfer)
✦ Il formato della rappresentazione deve
essere concordato tra il client e il server
6
7. Rappresentazioni
✦ Ciascuna risorsa può avere più
rappresentazioni diverse
• Ad esempio, le risorse del nostro sito di
commercio elettronico possono essere
rappresentate:
‣ in formato HTML per la visualizzazione ad un utente che
accede mediante un browser web
‣ in formato PDF per la stampa
‣ in formato XML per consentire l’elaborazione da parte di
un’altra applicazione
‣ in formato JSON per consentire l’elaborazione da parte di
un JavaScript presente in una pagina web
7
8. Rappresentazioni
✦ Nel protocollo HTTP, il formato di una
risorsa viene identificato attraverso la
codifica definita nello standard MIME
(Multimedia Internet Mail Extension)
✦ Un “MIME type” è specificato da una
stringa che ha come formato:
• type/subtype
• type/subtype; options
8
9. Rappresentazioni
✦ I nomi dei tipi MIME sono assegnati
dall’IANA (Internet Assigned Number
Authority)
✦ Esempi:
• text/plain formato testo semplice
• text/plain; charset=UTF-8 testo semplice
• text/html formato HTML
• application/xml formato XML
• image/jpeg formato JPEG
9
10. Operazioni
✦ Nell’approccio REST si usa un numero
limitato di operazioni per leggere o
modificare lo stato delle risorse
✦ Le operazioni corrispondono ai “metodi”
definiti nel protocollo HTTP
✦ Non tutte le operazioni sono disponibili su
tutte le risorse
10
11. Operazioni: GET
✦ L’operazione GET consente di ottenere
una rappresentazione della risorsa
✦ È l’operazione di default per i browser
web
✦ Non deve modificare lo stato delle risorse
• il risultato dell’operazione può essere
temporaneamente mantenuto in una cache per
migliorare le prestazioni
11
12. Operazioni: GET
✦ Nota: alcune web applications usano GET
anche per modificare lo stato delle risorse
• vantaggio: l’operazione GET è semplice da testare
usando un browser web
• svantaggio: problemi con cache, proxy e altri
componenti dell’infrastruttura del web
• l’uso di GET per operazioni che modificano lo stato
è considerato una violazione della filosofia REST
12
13. Operazioni: PUT
✦ L’operazione PUT modifica lo stato di una
risorsa, o crea la risorsa se l’URL
specificato non ha una risorsa
corrispondente
✦ I browser web normalmente non usano
PUT, ma le “cartelle web” disponibili nei
principali sistemi operativi consentono di
usare questa operazione per scrivere su
un server (se il server lo permette)
13
14. Operazioni: DELETE
✦ L’operazione DELETE cancella una risorsa
dal server
✦ Anche questa operazione non è
normalmente usata da un browser, ma
supportata da altri client come le “cartelle
web”
14
15. Operazioni: POST
✦ L’operazione POST è usata per l’aggiunta
di nuove risorse a una collezione
✦ È usata dai browser web per l’invio dei
form
✦ A differenza di GET, PUT e DELETE,
l’operazione POST non è idempotente:
eseguire due volte la stessa operazione
produce uno stato diverso da una singola
esecuzione
15
16. Operazioni: POST
✦ Per la creazione di nuove risorse si può
usare sia PUT che POST
• PUT richiede di specificare l’URL della risorsa da
creare; va usata quando si desidera che sia il
client a decidere l’URL delle nuove risorse
• POST richiede di specificare l’URL della collezione
che conterrà la risorsa da creare; va usata
quando si desidera che sia il server a decidere
l’URL delle nuove risorse
16
17. Operazioni: POST
✦ Diverse applicazioni usano solo i metodi
GET e POST; tutte le operazioni che
modificano lo stato sono codificate
usando POST con opportuni parametri
• vantaggio: è possibile testare le operazioni
usando un form HTML
• questa soluzione è considerata una parziale
violazione della filosofia REST
✦ XML-RPC e SOAP codificano le richieste di
esecuzione di un metodo in un’operazione
POST
17
18. Esecuzione di un’operazione
✦ Il protocollo HTTP ha una struttura
richiesta/risposta, in cui ogni interazione
viene considerata indipendente dalle altre
(il protocollo è stateless)
• il client invia la richiesta
• il server elabora la richiesta
• il server invia la risposta, contenente
eventualmente un’indicazione di errore
18
19. Esecuzione di un’operazione
✦ Una richiesta HTTP contiene:
• l’URL della risorsa a cui è riferita
• l’operazione da effettuare (es. GET)
• informazioni aggiuntive (headers), ad esempio
per indicare il tipo di rappresentazione richiesta
• per alcune operazioni, un “corpo” della richiesta
(body); in particolare il body è presente nelle
operazioni PUT e POST
19
20. Esecuzione di un’operazione
✦ Una risposta HTTP contiene:
• un codice numerico che indica l’esito
dell’operazione (status)
• informazioni aggiuntive (headers); ad esempio, il
tipo di rappresentazione restituito
• per alcune operazioni, un “corpo” della risposta
(body)
20
21. Status
✦ Lo status è codificato su 3 cifre
✦ La prima cifra indica l’esito generale:
• 2xx: operazione eseguita con successo
• 3xx: redirezione (la risorsa desiderata si trova a
un altro indirizzo)
• 4xx: errore da parte del client
• 5xx: errore interno al server
21
22. Status
✦ Le due cifre successive forniscono
maggiori dettagli. Ad esempio:
‣ 200: OK
‣ 201: OK, creata nuova risorsa con URL specificato negli
header
‣ 204: OK senza response body
‣ 301: Redirezione permanente
‣ 307: Redirezione temporanea
‣ 401: Utente non autorizzato a eseguire l’operazione
‣ 404: Risorsa non trovata
‣ 501: Metodo non implementato
‣ 505: Versione del protocollo non supportata
22
23. Definizione di un WS
✦ Nella definizione del web service, occorre
specificare:
• quali operazioni sono permesse per ciascun URL
• quali formati sono accettati per il body della
richiesta e della risposta
• i codici di stato restituiti
✦ La definizione è solitamente informale,
ma sono stati proposti linguaggi per la
descrizione di un WS RESTful:
• WSDL 2.0
23
• WADL
24. Client in Java
✦ Un client RESTful deve:
• individuare la risorsa di cui vuole consultare o
modificare lo stato
• preparare una richiesta indicando l’operazione da
effettuare e le altre informazioni aggiuntive
• inviare la richiesta e ottenere la risposta
• esaminare lo status della risposta ed estrarre le
informazioni di interesse dal body e dagli header
✦ Le classi necessarie sono: URL e
HttpURLConnection, definite in java.net
24
25. La classe URL
✦ Consente di costruire un URL,
eventualmente a partire da un URL
relativo
✦ Consente di creare una connessione alla
risorsa identificata dall’URL (istanziando
la classe HttpURLConnection)
25
26. La classe URL
✦ Costruttori:
• URL(String url) throws MalformedURLException
• URL(URL base, String relativePart) throws
MalformedURLException
‣ il secondo costruttore produce un URL relativo a partire
dall’URL base
✦ Esempio:
public static void main(String args[]) throws Exception {
URL base=new URL("http://nerone.diiie.unisa.it/plone/adinf/");
URL corso=new URL(base, "Corsi_new/Informatica Magistrale/Programmazione in Rete");
System.out.println(corso);
}
26
27. HttpURLConnection
✦ Per connettersi alla risorsa occorre usare
un oggetto della classe
HttpURLConnection
✦ Tale oggetto viene costruito dal metodo
openConnection() di URL:
• URLConnection openConnection() throws
IOException;
‣ NOTA: poiché il valore di ritorno è un URLConnection,
occorre un cast per ottenere un HttpURLConnection
27
28. HttpURLConnection
✦ Una volta ottenuto l’oggetto che
rappresenta la connessione, occorre:
• impostare il metodo e, se necessario, gli header
della richiesta
• chiamare il metodo connect() per attivare la
connessione
• inviare (se necessario) il request body
• leggere lo status code e, se necessario, gli header
della risposta
• leggere il body della risposta
28
29. Preparazione
✦ Per impostare il metodo HTTP da usare,
occorre richiamare:
• void setRequestMethod(String method) throws
IOException;
‣ Nota: il nome dei metodi HTTP è case sensitive; occorre
usare “GET” e non “get”.
‣ Nota: per default la classe usa il metodo GET
29
30. Preparazione
✦ È possibile specificare gli header della
richiesta con il metodo:
• void setRequestProperty(String name, String
value)
✦ Tra gli header della richiesta più
importanti:
• “Content-Type”: tipo MIME del request body
• “Accept”: lista (separata da virgole) dei tipi MIME
accettati per il response body
30
32. Preparazione
✦ In fase di preparazione occorre
specificare se sarà presente un request
body e/o un response body con i metodi:
• void setDoOutput(boolean on);
‣ se il parametro true, ci sarà un request body
• void setDoInput(boolean on);
‣ se il parametro è true, ci sarà un response body
✦ Per default la connessione assume che ci
sia un response body ma non un request
body
32
33. Connessione
✦ Dopo la preparazione, l’accesso alla
risorsa viene iniziato usando il metodo:
• void connect() throws IOException
✦ Una volta avviata la connessione è
possibile inviare il request body (se
necessario) e quindi leggere la risposta
✦ L’oggetto HttpURLConnection richiama
automaticamente connect quando viene
usato uno dei metodi che richiedono la
connessione
33
34. Invio del request body
✦ È possibile inviare il request body al
server attraverso un output stream
ottenuto dal metodo:
• OutputStream getOutputStream() throws
IOException
✦ NOTA: i dati sono bufferizzati in memoria,
e inviati solo al momento in cui è
eseguito il metodo close dell’output
stream
34
35. Uso della risposta
✦ Per leggere lo status della risposta:
• int getResponseCode() throws IOException
✦ Per leggere il body della risposta:
• String getContentType(); // tipo MIME della
risposta
• InputStream getInputStream() throws
IOException; // stream attraverso cui leggere il
dato
‣ NOTA: occorre usare il metodo close() dello stream per
assicurarsi che vengano rilasciate le risorse (es. socket
TCP) usate dalla connessione
35
36. Esempio
✦ Esempio di una operazione GET
import java.net.*;
import java.io.*;
public class EsempioGet {
public static void main(String args[]) throws Exception {
URL url=new URL("http://en.wikipedia.org/wiki/Representational_State_Transfer");
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
int status=conn.getResponseCode();
System.out.println("RESPONSE CODE: "+status);
System.out.println("CONTENT TYPE: "+conn.getContentType());
if (status>=200 && status<=299) {
InputStreamReader in=new InputStreamReader(conn.getInputStream(), "UTF-8");
int c;
while ((c=in.read())!=-1)
System.out.print((char)c);
}
}
}
36
37. URL encoding
✦ Per passare i contenuti di un form al
server web è stato definito il tipo
application/x-www-form-urlencoded
• usato normalmente per il request body
dell’operazione POST nell’invio di form
• può essere usato per passare informazioni
aggiuntive anche alle altre operazioni (es. GET)
inserendo i dati nella URL dopo un ‘?’ (query
string)
37
38. URL encoding
✦ Un contenuto di questo tipo è costituito
da un insieme di coppie (chiave, valore)
codificate in una stringa, usando ‘&’ per
separare le coppie e ‘=’ per separare
chiavi e valori:
• chiave1=valore1&chiave2=valore2&...
✦ Le chiavi e i valori devono essere
codificati usando una codifica detta URL
encoding per proteggere i caratteri
speciali (es. / o &) che hanno un
significato in una URL
38
39. URL encoding
✦ Le classi URLEncoder e URLDecoder
forniscono metodi per codificare/
decodificare l’URL encoding
✦ In particolare, per la codifica si usa il
metodo statico di URLEncoder:
• static String encode(String value, String charset);
✦ Nota:
• lo standard dice che il charset da usare per la
query string è UTF-8 mentre per il request body
va specificato nel tipo MIME; in pratica molti
server scelgono un charset fisso
indipendentemente dalla richiesta
39
40. Esempio
✦ Un esempio completo di POST
import java.net.*;
import java.io.*;
import java.util.*;
public class EsempioPost {
public static String encodeForm(Map<String,String> data) {
StringBuffer sb=new StringBuffer();
try {
for(String key : data.keySet()) {
sb.append(URLEncoder.encode(key, "UTF-8"));
sb.append('=');
sb.append(URLEncoder.encode(data.get(key), "UTF-8"));
sb.append('&');
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unsupported encoding UTF-8");
}
return sb.toString();
}
// continua
40
41. Esempio
✦ Un esempio completo di POST (continua)
public static void main(String args[]) throws Exception {
URL url=new URL("http://www.myservice.com/orders");
Map<String,String> form=new HashMap<String,String>();
form.put("user", "pippo");
form.put("product", "xyz123");
form.put("quantity", "5");
String body=encodeForm(form);
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded; charset=UTF-8");
conn.setDoOutput(true);
PrintWriter pw=new PrintWriter(
new OutputStreamWriter(
conn.getOutputStream(), "UTF-8"));
// continua
41
42. Esempio
✦ Un esempio completo di POST (continua)
pw.print(body);
pw.close();
int status=conn.getResponseCode();
System.out.println("RESPONSE CODE: "+status);
System.out.println("CONTENT TYPE: "+conn.getContentType());
if (status>=200 && status<=299) {
InputStreamReader in=new InputStreamReader(conn.getInputStream(), "UTF-8");
int c;
while ((c=in.read())!=-1)
System.out.print((char)c);
in.close();
}
}
}
42