22 giugno 2009

Richieste HTTP GET, POST, REST con Android

Dopo il tutorial su cos'è rest ecco un' implementazione per poter utilizzare REST sulla piattaforma Android.

In particolare ciò che ho creato è una classe di utilità in cui sono presenti una serie di metodi utili per l'esecuzionedi richieste di tipo GET e POST ed un wrapper mediante il quale è possibile eseguire una chiamata REST modellata in base al tipo di method che gli si passa in input.

public class RestUtils {
private final static String METHOD_POST = "post";
private final static String METHOD_GET= "get";
private final static String TAG= "RestUtils";

/***
* Esegue una richiesta REST
*
* @param host : hostname
* @param method : methodo (GET,POST supportati per ora)
* @param path : percorso
* @param parameters : parametri
* @return : Stringa contenente la response
* @throws RestRequestException : Eccezione personalizzata
*/
public static String doRESTRequest (String host, String method, String path, Map<String,String> parameters)
throws RestRequestException{

return doRESTRequest(host, "80", method, path, parameters);
}

/***
* Esegue una richiesta REST
*
* @param host : hostname
* @param port : porta
* @param method : methodo (GET,POST supportati per ora)
* @param path : percorso
* @param parameters : parametri
* @return : Stringa contenente la response
* @throws RestRequestException : Eccezione personalizzata
*/
public static String doRESTRequest (String host, String port, String method, String path, Map<String,String> parameters)
throws RestRequestException{

String returnString = null;
try{

String url = host+":"+port+path;
Log.i(TAG,METHOD_GET+" Request - URL : "+url );

if (METHOD_GET.equalsIgnoreCase(method)){
returnString = doGETRequest(url,parameters);
}else if (METHOD_POST.equalsIgnoreCase(method)){
returnString = doPOSTRequest(url, parameters);
}
}catch(GetRequestException e){
throw new RestRequestException(e.getMessage());
}catch(PostRequestException e){
throw new RestRequestException(e.getMessage());
}

return returnString;

}

/***
* Metodo per eseguire una request di tipo GET
* @param url : url della request
* @return : stringa contenente la response
* @throws GetRequestException : Eccezione modellata
*/
public static String doGETRequest(String url,Map<String, String> parameters) throws GetRequestException{
String paramStr = composeParametersForGetRequest(parameters);

if (paramStr!=null && paramStr.length() > 0 ) url = url +"?"+paramStr;
String websiteData = null;

try {
Log.i(TAG,"GetRequest - url : "+url);
DefaultHttpClient client = new DefaultHttpClient();
URI uri = new URI(url);
HttpGet method = new HttpGet(uri);
HttpResponse res = client.execute(method);
InputStream data = res.getEntity().getContent();
websiteData = parseISToString(data);
} catch (ClientProtocolException e) {
throw new GetRequestException(e.getMessage());
} catch (IOException e) {
throw new GetRequestException(e.getMessage());
} catch (URISyntaxException e) {
throw new GetRequestException(e.getMessage());
}finally{
Log.i(TAG,"GetRequest - Request & Response completed");
}
return websiteData;
}

public static String doPOSTRequest(String url,Map<String, String> parameters)
throws PostRequestException{

String returnString = null;
// Creo un nuovo HttpClient e l'Header del post
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
httppost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded");

try {
// aggiungo i dati alla richiesta
List<NameValuePair> nameValuePairs = composeParametersForPostRequest(parameters);
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

// Eseguo la richiesta HTTP
HttpResponse response = httpclient.execute(httppost);
if (response.getStatusLine().getStatusCode() == 200) {
returnString = EntityUtils.toString(response.getEntity());
response = null;

}
} catch (ClientProtocolException e) {
throw new PostRequestException(e.getMessage());
} catch (IOException e) {
throw new PostRequestException(e.getMessage());
}

return returnString;

}

public static List<NameValuePair> composeParametersForPostRequest(Map<String,String> parameters){

List<String> chiavi = new ArrayList<String>(parameters.keySet());
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();

for (int i = 0 ; i < chiavi.size(); i++){
String chiave = chiavi.get(i);
nameValuePairs.add(new BasicNameValuePair(chiave, parameters.get(chiave)));
}

return nameValuePairs;
}

/***
* Metodo per comporre la parte di URL relativa ai parametri
* @param parameters : mappa di parametri
* @return : Stringa contenente i parametri concatenati
*/
public static String composeParametersForGetRequest(Map<String, String> parameters){
String paramStr = "";
List<String> chiavi = new ArrayList<String>(parameters.keySet());

for (int i = 0 ; i < chiavi.size(); i++){
String chiave = chiavi.get(i);
paramStr += chiave+"=";
paramStr += URLEncoder.encode(parameters.get(chiave));
paramStr += "&";
}
return paramStr;
}
}


Innanzitutto noterete che mancano alcune componenti per cui non potrete compilare questa classe:
- Metodi per la conversione da Stringa ad InputStream e viceversa che potrete trovare su questo post.
- Eccezioni personalizzate...potete ricrearvele voi, l'importante è che estandano Exception.

Adesso analizziamo i metodi :
- doRESTRequest : ci sono 2 overload utilizzabili uno in cui è possibile utilizzare una porta diversa da quella di default (80). Tramite questo metodo è possibile eseguire qualsiasi tipo di richiesta REST in base al parametro method che può essere "get" o "post". Gli altri parametri sono facilmente intuibili e troverete un esempio più avanti.
- doGETRequest : è un metodo che dato un url ed una mappa di parametri esegue una richiesta di tipo GET e restituisce una stringa contenente la response.
- doPOSTRequest : è un metodo che dato un url e una mappa di parametri esegue una richiesta di tipo POST e restituisce una stringa contenente la response.
- composeParametersForPostRequest : metodo per comporre i parametri in maniera adeguata per poter eseguire una richiesta di tipo POST.
- composeParametersForGetRequest : metodo per comporre i parametri in maniera adeguata per completare l'url per una richiesta di tipo GET.

Vediamo un esempio di utilizzo della classe di utilità per una richiesta di tipo POST. L'esempio utilizza le API REST di Yahoo per eseguire una ricerca :

Map<String,String> paramz = new HashMap<String,String>();
paramz.put("appid", "YahooDemo");
paramz.put("query", "umbrella");
paramz.put("results", "10");
try {
String retString = RestUtils.doRESTRequest("http://api.search.yahoo.com", "POST", "/WebSearchService/V1/webSearch", paramz);
Log.i(TAG,"Return : "+retString);
} catch (RestRequestException e) {
Log.e(TAG,"Eccezione : ",e);
}


Spero che questo post vi sia stato di aiuto.
Accetto domande e proponimenti a riguardo.

1 commento:

Andrea ha detto...

Grazie per il tutorial, ma per path cosa intendi che non capisco? cordiali saluti Andrea