Upload
whymca
View
848
Download
0
Embed Size (px)
Citation preview
Luca Masini - @lmasiniLuca Masini - @lmasiniGTUG FirenzeGTUG Firenze
SVILUPPO DI SERVIZI REST PER ANDROID
Ovvero tutto quello che abbiamo imparato sviluppando servizi REST per
applicazioni Mobile
Agenda• Obiettivi• Architettura e infrastruttura • REST e Livello 3 • Frameworks • Multiplatform• Security• Versioning• Caching
Obiettivi
• I servizi coprono:–Aree informative–Asset Digitali–Ricerche su basi dati enterprise–Servizi online
per un totale di circa 30 end-point
Obiettivi
• Realizzare servizi usabili da client diversi...
come sistema operativocome layout grafico come risorse a disposizione
• Non si tratta quindi di API REST, ma di servizi per un'applicazione specifica
Architettura e infrastruttura • Internet è sia architettura che infrastruttura• Il supporto tecnologico è diffuso (Java, .NET,
Python..) per la realizzazione di RESTful services• Cloud non ha problemi di banda (ma i parametri
TCP/IP devono essere ottimizzati per il 3G)• La scalabilità è assicurata (e dunque le
performance) da:– Massimo disaccoppiamento (un link!)– Caching (anche solo con 304 !!) – Proxy
REST e livello 3 • Il RMM definisce quattro livelli di maturità a seconda di
quanto si usino HTTP, URI ed Hypermedia, partendo dallo zero per i servizi che non usano alcuno di questi (tipicamente SOAP !)
• Un servizio di “maturità 3” ha la caratteristica di:– Indirizzare la risorsa tramite la URL– Usare i verbi HTTP per indicare l'azione sulla risorsa – Esporre una rappresentazione in grado di "guidare" lo
sviluppatore o la macchina a stati finiti verso l'esplorazione del sistema (HATEOAS)
Frameworks Server• La realizzazione di RESTful services è assicurata da
ogni tecnologia server-side:– Windows Communication Foundation (WCF)
per .NET– Il mondo Java ha una specifica proprio indirizzata
a REST, ovvero JAX-RS (ora in corso di definizione la 2.1) e due implementazioni maggiori:• RESTEasy di Jboss• Jersey (la RI)
– Spring implementa REST tramite i RequestMapper del framework MVC
Frameworks Client• Chiamare i servizi REST con Apache
HTTP Client è come sviluppare Servlet partendo dal socket !!
• Possiamo usare lo stesso idioma del server con librerie come resteasy-client-mobile
Frameworks Client
Definizione servizio:@Path("/1/boards")
public interface BoardService {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{boardid}/lists")
List<CardContainer> findListsForBoard(@PathParam("boardid") String boardid,
@QueryParam("key") String key);
}
invocazione del servizio:BoardService service = ProxyFactory.create(BoardService.class,"https://api.trello.com");
List<CardContainer> lists = service.findListsForBoard(boardId, SplashScreenActivity.testKey);
Multiplatform• Realizzare servizi per piattaforme diverse
comporta la risoluzione di alcuni problemi:– Diversificazione dell'informazione inviata al
client in base alle sue "capacità" (ad es. risoluzione/dimensione schermo)
– Modalità diverse di rendering e rappresentazione (ad es. i volantini)
– Wireframe diversi per versioni HD e non, che però non giustificano nuovi end-point
Security• Più che la sicurezza lato end-user,
comunque importante, il focus è stato spostato sull'evitare che applicazioni terze parti possano usare questi servizi REST
• E' l'antitesi di quello che tutti fanno oggi, ovvero rendere disponibili i dati
Security // Carica certification authority in formato BKS InputStream clientTruststoreIs =
getResources().openRawResource(R.raw.certification_authority); KeyStore clientCertificate = KeyStore.getInstance("BKS"); clientCertificate.load(clientTruststoreIs, "verysecretpassword".toCharArray()); System.out.println("Loaded certification authority: " + clientCertificate.size());
// Carica client certificate InputStream keyStoreStream = getResources().openRawResource(R.raw.client_certificate); KeyStore keyStore = KeyStore.getInstance("pkcs12"); keyStore.load(keyStoreStream, "Another Super Secret Password".toCharArray());
System.out.println("Loaded client certificates: " + keyStore.size());
// Crea la SSLSocketFactory con SSLSocketFactory socketFactory =
new SSLSocketFactory(keyStore, "trust",clientCertificate);
// Configura parametri chiamata HTTP HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, "UTF-8"); HttpProtocolParams.setUseExpectContinue(params, true); HttpProtocolParams.setUserAgent(params, "CompanyApp 1.0");
Security // Facciamo un ESSENZIALE pool per le connessioni su questo socket !!!! ConnPerRoute connPerRoute = new ConnPerRouteBean(12); ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute); ConnManagerParams.setMaxTotalConnections(params, 20);
// Set timeout HttpConnectionParams.setStaleCheckingEnabled(params, false); HttpConnectionParams.setConnectionTimeout(params, 20 * 1000); HttpConnectionParams.setSoTimeout(params, 20 * 1000); HttpConnectionParams.setSocketBufferSize(params, 8192);
// Non seguo redirect HttpClientParams.setRedirecting(params, false);
// Registro https con il nostro SSLSocketFactory SchemeRegistry schReg = new SchemeRegistry(); schReg.register(new Scheme("https", socketFactory, 443)); ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg); DefaultHttpClient sClient = new DefaultHttpClient(conMgr, params);
// Finalmente faccio sta benedetta chiamata HttpGet httpGet = new HttpGet("https://mobile.company.it/services/store/STOREID"); HttpResponse response = sClient.execute(httpGet); HttpEntity httpEntity = response.getEntity();
Versioning• L'evoluzione di un'app porta ad avere distribuiti
client di versioni diverse sui device degli utenti
• Le nuove caratteristiche portano a sviluppare nuovi servizi
Versioning• La criticità si ha quando servizi esistenti devono
tornare dati nuovi rimanendo compatibili !!!!!!
{
sigla: "NEG",
descrizione: "Negozio",
indirizzo: "Via dei Servizi REST",
cap: "50135",
comune: "Firenze",
provincia: "FI",
UrlDettaglio: “https://url.to.detail” // <== Nuovo attributo}
Versioning• La criticità si ha quando servizi esistenti devono
tornare dati nuovi rimanendo compatibili !!!!!!
{
sigla: "NEG",
descrizione: "Negozio",
indirizzo: "Via dei Servizi REST",
cap: "50135",
comune: "Firenze",
provincia: "FI",
UrlDettaglio: “https://url.to.detail” // <== Nuovo attributo}
Versioning• Il problema del versioning si può mitigare
tramite un corretto uso di JSON, delle API/User-Agent e scrivendo fin da subito client che sono molto "permissivi" a riguardo dei dati che ricevono
@SourceServiceVersions(@SourceServiceVersion(versionTag = VersionTag.HD, targetMethod = "methodForHD")
) @Override public List<Map<String, Object>> defaultMethod(String info) {}
@TargetServiceVersions(value = {VersionTag.HD}) public List<Map<String, Object>> methodForHD(String info) {}
Caching• HTTP ed Internet hanno già implicito il concetto di caching, che
deve essere implementato però dai nostri servizi e dai nostri client, rispettando i verbi HTTP e gli header di caching.
• Purtroppo le librerie HTTP delle piattaforme mobile mancano di molti dei concetti che i browser implementano da decenni
• Vista l'alta latenza del 3G è importante pensare ad implementare anche back-end caches dei nostri servizi (memcached) o l'uso di back-end adatti al cloud (NoSQL)
Luca Masini - @lmasiniLuca Masini - @lmasiniGTUG FirenzeGTUG Firenze
Domande ??
Firenze GTUG Google Technology User Group - Firenze
Group: [email protected]
Blog: http://firenze-gtug.blogspot.it/
...presto GDG
Site: http://sites.google.com/site/firenzegtug/
Google Developer Group