Quando realizziamo un app dobbiamo spesso consentirle di comunicare con un server per inviare o ricevere messaggi.
Spesso questa comunicazione avviene attraverso una web service, cioè (generalizzando e semplificando molto) un servizio reso disponibile attraverso una rete distribuita che fa uso del protocollo HTTP per il trasporto dei messaggi.
Cos’è REST e cosa c’entra con la comunicazione della nostra app?
REST sta per REpresesentational State Transfer ed è un insieme di principi architetturali per la progettazione di un sistema di ipertesto distribuiti. Sarebbe interessante, ma non voglio dilungarmi al riguardo in questo articolo. Per adesso ci basta sapere che vengono definiti dei vincoli che riguardano la comunicazione di un client con un server. Questi vincoli stabiliscono che la comunicazione deve essere costituita da un’interfaccia uniforme, che il server non deve memorizzare nessun contesto tra una comunicazione e l’altra (stateless), …
Un concetto fondamentale è l’esistenza delle risorse a cui si può accedere tramite un identificatore globale (URI: Uniform Resource Interface). Il client deve solo sapere qual è l’URI per accedere alla risorsa, gli eventuali parametri (ID della risorsa ad esempio) e il formato di rappresentazione che generalmente (e in questo articolo) è il JSON (guarda come è semplice lavorare in JSON con Swift 4).
(Se vuoi una classe Swift pronta come base per un client: https://mirchaemanuel.com/una-classe-swift-per-un-client-webservice/
Un webservice che implementa l’architettura REST, che quindi mette a disposizione le sue risorse adottando i principi elencati, viene definito RESTful.
Le API di una webservice RESTful sono costituite da un URI e un metodo HTTP. Vengono utilizzati i metodi GET, PUT, POST, DELETE rispettivamente per accedere, modificare, inserire o cancellare le risorse messe a disposizione dalla webservice.
Ad esempio, se ho un servizio web che rende disponibile una rubrica alla mia app. Posso definire un URI per accedere alle risorse:
http://ws.mioserver.com/contacts/1
Effetuando un GET con questa URI viene reso disponibile il primo contatto e rappresentato in JSON:
{ "error": false, "errorMessage": "", "contact": { "id": "1", "name": "mircha emanuel", "phone": "0123321123", "email": "[email protected]" } }
Se la webservice lo permette, effettuando un DELETE con lo stesso URI, il contatto verrebbe eliminato dal server.
Un vero standard di queste API non esiste, dato che REST è solo un insieme di linee guida. La maggior parte degli sviluppatori mette a disposizione le risorse RESTful attraverso i metodi HTTP, accessibili da URI e rappresentati (serializzati) in JSON. In questo articolo mostreremo come la nostra app può comunicare con una webservice che soddisfa le caratteristiche appena menzionate.
Client REST in Swift
Il nostro client deve essere in grado di effettuare una richiesta HTTP con un metodo tra GET, PUT, POST e DELETE su un URI e ottenere in risposta un JSON che rappresenta la risorsa o il response.
URI
Dobbiamo comunicare con un server remoto, il nostro URI sarà un URL. Foundation rende disponibile la classe URL. Per ottenere un’istanza di URL che rappresenta l’indirizzo della nostra risorsa, possiamo semplicemente usare il costruttore in questo modo:
let resourceUrl = URL(string: "http://ws.mioserver.com/contacts/1")
Richiesta HTTP
Abbiamo l’URL, dobbiamo “contattarlo”. Definiamo il nostro oggetto URLRequest che serve ad incapsulare le informazioni della nostra richiesta (URL, metodo, …).
URLRequest conterrà anche le informazioni sul metodo HTTP richiesto per accedere alla risorsa:
let urlRequest = URL(string: "http://ws.mioserver.com/contacts/1")! var request = URLRequest(url: urlRequest) request.httpMethod = "GET"
(il metodo GET è implicito, andrebbero specificati solo gli altri metodi)
Connessione alla URLRequest
Il framework Foundation mette a disposizione la classe URLSession per permettere di richiedere del contenuto in rete. È un classe che permette di definire diversi parametri della connessione e che supporta diversi URL Scheme, proxy, …
Dato che una richiesta RESTful non richiede nulla di particolare, possiamo richiedere l’istanza di URLSession attraverso il metodo shared.
La connessione può avvenire in maniera sincrona o asincrona. Nel nostro esempio effettuato la richiesta con un task asincrono.
Il task di connessione va creato con il metodo dataTask di URLSession e poi avviato chiamando il metodo resume().
È necessario definire l’handler completionHandler per elaborare la risposta della webservice. Al termine della comunicazione viene invocato l’handler con tre parametri:
- data
- il dato ritornato dal server
- response
- un oggetto che contiene la risposta del server come HTTURLResponse e fornisce l’header HTTP, lo status code, …
- error
- indica il fallimento della connessione, nil se la richiesta è avvenuta con successo.
Vediamo in pratica come effettuare la nostra richiesta. Effettueremo una richiesta ad un servizio che fornisce l’indirizzo IP del client:
let urlRequest = URL(string: "https://httpbin.org/ip")! var request = URLRequest(url: urlRequest) request.httpMethod = "GET" //definisco il metodo let session = URLSession.shared //richiedo l'istanza condivisa let task = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in //verifico la presenza di errori guard error == nil else { print(error!) return } //verifico la presenza di dati nella risposta guard let data = data else { print("no data") return } //effettuo una deserializzazione del dato in JSON let json = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject] print("IP: \(json["origin"] as? String ?? "")") }) task.resume()
Se tutto andrà per il verso giusto, otterremo questo in output:
["origin": 93.41.102.155] IP: 93.41.102.155
Conclusioni
Ho illustrato brevemente e superficialmente i concetti di una webservice RESTful e come realizzare, con poche righe Swift, un client che richiede dei dati e li deserializza.
Tornerò presto a parlare di webservice RESTful mostrandovi un esempio concreto e magari anche come realizzare un vostro servizio 🙂
Stay tuned…