C'est parti ! Accrochez vos ceintures ! Nous allons lancer notre première requête !
Créez le fichier
Les appels réseaux concernent la logique de l'application, et ont donc lieu dans le modèle. On va donc rajouter un fichier QuoteService.swift
dans le modèle.
Dans ce fichier, créez la classe QuoteService
, vide pour l'instant.
Créez la requête
Souvenez-vous, pour faire un appel réseau, il nous faut une instance URLSession
qui lance une URLSessionTask
, cette dernière étant initialisée avec une URLRequest
. Nous allons commencer par créer cette requête.
Pour cela, nous avons besoin de l'URL. Comme on l'a vu dans le chapitre avec Postman, l'URL, la voici : http://api.forismatic.com/api/1.0/ . Je vous propose de la rajouter dans la classe sous la forme d'une constante de classe privée :
private static let quoteUrl = URL(string: "https://api.forismatic.com/api/1.0/")!
Maintenant, nous allons créer une fonction statique que nous allons appeler simplement getQuote
, et à l'intérieur de laquelle nous allons créer notre requête :
static func getQuote() {
var request = URLRequest(url: quoteUrl)
request.httpMethod = "POST"
}
J'initialise une instance de URLRequest
en lui passant notre URL en paramètre. Ensuite, je précise la méthode HTTP choisie (en l'occurrence POST
) avec la propriété httpMethod
de URLRequest
.
Par ailleurs, nous avons besoin de passer des paramètres dans cette requête. Nous allons les rajouter avec la propriété body
de URLRequest
:
let body = "method=getQuote&lang=en&format=json"
request.httpBody = body.data(using: .utf8)
J'écris les paramètres sous la forme d'une chaîne de caractères. Vous reconnaissez les paramètres que l'on a utilisés précédemment avec Postman. Ensuite, j'utilise la méthode data(using:)
du type String
, qui permet de convertir une chaîne de caractères vers le format Data
. Et je précise l'encodage de mon choix, en l'occurrence utf8
, le plus courant dans l'univers du développement.
Et voilà, notre requête est créée, nous avons précisé son URL, sa méthode et ses paramètres. On va pouvoir créer et lancer notre tâche !
Lancez la tâche
On l'a vu au chapitre précédent, pour lancer une tâche, il faut une instance d'URLSession
. Pour cela, nous allons créer une instance d'URLSession
avec une configuration par défaut :
let session = URLSession(configuration: .default)
Ensuite, nous allons créer une tâche, et plus précisément une instance de URLSessionDataTask
:
let task = session.dataTask(with: request) { (data, response, error) in
}
Plusieurs choses ici :
On crée une tâche qu'on stocke dans la constante task.
Pour cela, on utilise la méthode dataTask de URLSession.
Elle prend en paramètre notre requête request de type URLRequest.
Elle admet un deuxième paramètre : une fermeture. C'est dans cette fermeture que nous allons gérer la réponse de l'appel. Il admet 3 paramètres, comme on l'a vu au chapitre précédent : data de type Data?, response de type URLResponse? et error de type Error?.
Notre tâche est maintenant créée et pour lancer l'appel, il ne nous reste plus qu'à écrire :
task.resume()
Et voilà ! Votre appel va être lancé !
Gérez la réponse
Lorsque l'on gère la réponse, nous allons vérifier qu'elle contient bien les données qui nous intéressent, et que nous n'avons pas d'erreur. Nous allons donc commencer par écrire ceci :
let task = session.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else {
// Si on devait gérer l’erreur, ce serait ici
return
}}
Attends attends ! Guard ? C’est quoi ça, guard ? 😲
Je sais, c’est un mot nouveau mais pas de panique, c’est juste une autre façon de gérer les erreurs, plus propre que le if. Nous rentrerons plus en détail dans la prochaine partie. Sachez seulement que si nous n’avons pas d’erreur, nous ne rentrerons pas dans la portée du guard et nous continuerons notre programme tranquillement.
Ensuite, nous allons contrôler que le status code
de la réponse est bien à 200 :
let task = session.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else {
// gérer l’erreur ici
return
}
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
// gérer ici l’erreur de status code
return
}
}
}
On vérifie d'abord que la réponse est bien du type HTTPURLResponse
, et ensuite que le code vaut bien 200.
Décodez les données JSON
Avec les vérifications que nous avons faites, nous savons maintenant que la requête renvoie bien des données, et qu'il n'y a pas d'erreur. Seulement, souvenez-vous, nous avons demandé à ce que les données soient au format JSON :
let body = "method=getQuote&lang=en&format=json" // <= ICI
Or, nous ne savons pas manipuler ce format en Swift. En Swift, on manipule des dictionnaires, des tableaux, des objets, mais pas des JSON !
Heureusement, il existe une classe qui va nous permettre de faire la conversion depuis le format JSON vers un dictionnaire Swift classique. Elle s'appelle : JSONDecoder
. Et elle a une méthode decode
qui renvoie un dictionnaire. Voici comment on l'utilise :
guard let responseJSON = try? JSONDecoder().decode([String: String].self, from: data) else {
// gérer l’erreur de décodage
return
}
guard let text = responseJSON["quoteText"],
let author = responseJSON["quoteAuthor"] else {
// gérer l’erreur ici
return
}
Woooooh...
Oui je sais, il y a pas mal de choses ici, mais à part la première ligne, rien de vraiment compliqué :
Ligne 1 : On utilise la méthode decode de
JSONDecoder
, qui prend en paramètre deux choses :le type attendu des données que l'on va recevoir, ici on s'attend à recevoir un dictionnaire qui a comme type
String
pour la clé et pour la valeur. Le.self
permet de faire référence au type ;les
data
reçues en réponse à l'appel réseau, et d'éventuelles options que nous laissons vides.
Lignes 6 et 7 : Comme on a déjà vu à quoi ressemblaient les données reçues grâce à Postman, on sait que la citation est stockée avec la clé quoteText, et l'auteur avec la clé quoteAuthor. On récupère du coup simplement les valeurs correspondantes.
Pour être encore plus efficace, je vous propose de gérer toutes les conditions en une fois, comme ceci :
guard let responseJSON = try? JSONDecoder().decode([String: String].self, from: data), let text = responseJSON["quoteText"],
let author = responseJSON["quoteAuthor"] else {
// gérer l’erreur de décodage
return
}
Ensuite, vous pouvez faire des prints sur les variables text et author, et vous devriez voir les citations s'afficher dans votre console en appuyant sur le bouton New Quote dans votre simulateur !
Et voilà ! Dans le prochain chap...
Hop hop hop ! Tu ne vas pas t'en sortir comme ça ! Tu n’aurais pas oublié quelque chose ?
Comment ça ?
C'est quoi ça : try? ?!
Aaaah ! Certes... Bon, pour la faire courte, certaines fonctions comme la fonction decode peuvent planter et dans ce cas, on dit qu'on essaie de lancer la fonction avec try?. Je ne vous en dis pas plus pour le moment pour qu'on ne s'éparpille pas. Mais c'est le sujet de la dernière partie de ce cours. Alors, heureux ?
Hmmm.... On va dire oui !
En résumé
Pour récupérer des données JSON en précisant des paramètres, vous devez créer une requête HTTP
POST
.Pour créer une requête HTTP
POST
:Configurez la classe
URLRequest
en précisant le type de méthode HTTP et les paramètres dans le body.Lancez la tâche en utilisant la classe
URLSession
et sa sous-classeURLSessionDataTask
.N’oubliez pas de faire un
task.resume()
en lançant la tâche, sinon la requête ne partira jamais !Décodez les données JSON pour extraire les informations dont vous avez besoin.
Vous savez désormais créer une requête POST. Dans le prochain chapitre, nous allons mettre en place le téléchargement de l'image aléatoire associée à la citation !