Suivez votre progression
Accueil Trailhead
Accueil Trailhead

Accès aux données Salesforce à l'aide des API REST

Objectifs de formation

Une fois cette unité terminée, vous pourrez :

  • générer une requête REST à l’aide de l’interface RestClient ;
  • recevoir la réponse REST de Salesforce ;
  • utiliser le kit de développement mobile pour traiter la réponse REST.

Envoi de requêtes REST

La classe RootViewController montre un aperçu des classes API REST dans le kit Mobile SDK. Examinons de plus près l’utilisation des classes API REST.

Utilisation des objets RestClient et RestRequest

Pour accéder aux données Salesforce via les API REST du kit de développement mobile, vous envoyez des requêtes à Salesforce et recevez les réponses dans votre application. Comment RootViewController envoie-t-il des requêtes sur le réseau ?

RestClient est votre point d’entrée vers tous les services REST. Les applications de Kit de développement mobile utilisent les méthodes RestClient pour fabriquer et envoyer des demandes REST. Vous accédez toujours à cette classe uniquement via son instance partagée :

RestClient.shared()

Voici la séquence d’envoi de requêtes (« send request ») standard démontrée dans la méthode loadView() :
  1. Créez et initialisez une instance RestRequest. RestClient fournit pour cela un choix élargi de méthodes d’usine. Notre exemple crée une requête SOQL, mais vous pouvez sélectionner la méthode RestClient qui vous convient.
  2. Envoyez l’objet de la requête à Salesforce. RestClient authentifie automatiquement la requête avec les identifiants de l’utilisateur actif.
Examinons le code.
  1. Dans Xcode, ouvrez le fichier RootViewController.swift.
  2. Recherchez la méthode loadView(). L’implémentation lit un code semblable à :
    override func loadView() {
        super.loadView()
        self.title = "Mobile SDK Sample App"
        let request = RestClient.shared.request(forQuery: "SELECT Name FROM Contact LIMIT 10")        
        RestClient.shared.send(request: request) { [weak self] (result) in
            switch result {
                case .success(let response):
                    self?.handleSuccess(response: response, request: request)
                case .failure(let error):
                     SalesforceLogger.d(RootViewController.self, 
                         message:"Error invoking: \(request) , \(error)")
            }
        }
    }
Après avoir appelé la méthode de la super-classe et défini le titre de la vue, cette méthode prépare et envoie une requête REST. Pour ce faire, elle utilise :
  • l’instance partagée RestClient, qui génère un objet de requête à envoyer à Salesforce par le réseau ;
  • l’objet RestRequest généré, qui contient une requête prédéfinie à l’API REST basée sur la chaîne SOQL fournie.
Pour traiter les réponses REST, RootViewController utilise la méthode suivante :
send(request: Request, _ completionBlock: @escaping (Result<RestResponse, RestClientError>) -> Void)
Avec cette méthode, vous fournissez une closure finale pour traiter la réussite ou l’échec. Si vous n’êtes pas familier avec la syntaxe de closure finale, voici comment cela fonctionne. Une closure est, syntaxiquement, un bloc fonctionnel. Elle peut prendre des arguments et renvoyer une valeur. Si le type du dernier argument d’une fonction est une closure, vous pouvez supprimer cet élément de la liste des paramètres. À la place, vous ajoutez la closure immédiatement après la parenthèse de fermeture de l’appel. Une closure finale simplifie votre syntaxe et est autonome en tant que résultat attendu de l’appel de fonction qu’elle suit.

Dans ce cas, la closure finale détermine l’état de la réponse en lisant les membres success et failure de l’argument result. En cas de réussite, la closure reçoit les données de réponse et les transmet à une fonction de gestion distincte. En cas d’échec, la closure reçoit le message d'erreur, l’enregistre et revient.

En procédant ainsi, vous pouvez envoyer des requêtes et acheminer les réponses à l’aide d’une closure d’achèvement. Peut-être avez-vous des questions. Par exemple, « que signifie cette ligne ? »
{[weak self] (response, urlResponse) in ...
Ou encore, « existe-t-il d’autres options ? » Poursuivez votre lecture pour y trouver des réponses.

Traitement des réponses REST

La réception et la consommation de données Salesforce nécessite la capacité d’intercepter des rappels réseaux asynchrones. Le kit de développement mobile définit deux options pour cette tâche :

méthode RestClient
Lorsque vous appelez la fonction send, vous fournissez une closure finale. Salesforce envoie la réponse du serveur, encapsulée en tant qu’objet iOS, à votre closure.
Le protocole RestClientDelegate
Vous définissez quatre fonctions de rappel qui reçoivent des réponses de réussite et d’échec. Lorsque votre application envoie une requête REST, elle désigne la classe qui implémente ce protocole en tant que cible de la réponse du serveur.

En Objective-C, il est plus élégant d’utiliser le protocole SFRestDelegate, l’équivalent de RestClientDelegate, au lieu de rappels de blocs en ligne. Toutefois, dans les applications Swift, l’avantage d'une syntaxe closure finale offre une solution encore meilleure. Cette structure permet d’obtenir un enchaînement lisible et naturel, de la formation de la requête à la consommation de la réponse. Les closures en ligne sont également plus faciles à coder que le protocole RestClientDelegate.

Utilisation de la méthode RestClient send(request:_:) Méthode

Observons de plus près comment le modèle d’application Swift code la méthode send(request:_:).

  1. La classe de modèle RootViewController utilise la méthode d’usinekit de développement mobile RestClient pour créer une requête SOQL.
    let request = RestClient.shared.request(forQuery: "SELECT Name FROM User LIMIT 10")
  2. La ligne suivante appelle la méthode send pour envoyer la requête à Salesforce. Cette méthode attend un argument de closure pour recevoir la réponse du serveur et gérer la réussite ou l’échec. Par exemple :
    let request = RestClient.shared.request(forQuery: "SELECT Name FROM User LIMIT 10")
    RestClient.shared.send(request: request) 
    { [weak self] (result) in
        switch result {
            case .success(let response):
                self?.handleSuccess(response: response, request: request)
            case .failure(let error):
                SalesforceLogger.d(RootViewController.self, 
                    message:"Error invoking: \(request) , \(error)")
        }
    }
    Vous avez maintenant une closure finale facile à repérer, ajoutée juste après la parenthèse fermante de la méthode.
  3. Lorsque la réponse arrive, la liste de capture de la closure reçoit un objet de réponse (result).
    { [weak self] (result) in
        
    }
    Vous remarquerez l’utilisation explicite de [weak self] pour remplacer la référence implicite à self. Comme les réponses REST sont asynchrones, vous ne pouvez pas faire confiance à la classe qui a défini la closure de réussite pour rester en mémoire lorsque la réponse arrive. Pour éviter des cycles de rétention inutiles, utilisez [weak self] puis validez self dans la closure avant de l’utiliser.
  4. Si la réponse indique la réussite, votre application peut continuer son flux prévu, pour afficher une liste des noms de contact dans sa vue du tableau. L’application modèle transmet la réponse à une autre méthode locale, handleSuccess(response:request:):
    case .success(let response):
        self?.handleSuccess(response: response, request: request)
  5. Pour les échecs, le Kit de développement mobile envoie à votre requête .failure un objet de réponse (error) de type Error. Cette application enregistre un message d’erreur, puis revient.
    case .failure(let error):
        SalesforceLogger.d(RootViewController.self, 
            message:"Error invoking: \(request) , \(error)")
            // Nothing more to do, so just return
Voici la fonction handleSuccess(response:request:).
func handleSuccess(response: RestResponse, request: RestRequest) {
    guard let jsonResponse  = try? response.asJson() as? [String:Any], 
        let records = jsonResponse["records"] as? [[String:Any]]  else {
            SalesforceLogger.d(RootViewController.self, 
                message:"Empty Response for : \(request)")
            return
    }
    SalesforceLogger.d(type(of:self), message:"Invoked: \(request)")
    DispatchQueue.main.async {
        self.dataRows = records
        self.tableView.reloadData()
    }
}
Cette fonction prend l’objet de réponse ainsi que l’objet de demande d’origine. Si tout se passe comme prévu, le Kit de développement mobile envoie à la requête .success un objet de réponse (result) de type Dictionary<String, Any>. Cependant, même si une demande réussit, le serveur peut renvoyer un résultat valide mais inutilisable, par exemple si vous avez envoyé une demande de suppression. La fonction handleSuccess(response:request:) prépare au pire en utilisant une instruction guard pour convertir la réponse au type attendu. Si la conversion réussit, cette fonction stocke les enregistrements demandés dans sa variable locale dataRows, puis indique à la vue du tableau de recharger ses données. Où la vue du tableau obtient-elle ses données ? C’est exact, de la variable dataRows.

Utilisation du protocole RestClientDelegate

En plus de clarifier le code, le protocole RestClientDelegate analyse la catégorie d’un échec et envoie la réponse d’échec à un gestionnaire spécifique à la catégorie. Si votre classe adopte le protocole RestClientDelegate, elle peut mettre en œuvre quatre fonctions de gestionnaire de réponses.

  • request(_:didLoadResponse:) : la requête a été traitée. Le délégué reçoit la réponse au format JSON. Ce rappel indique la réussite. Il contient le même code que vous aviez intégré à la closure de réussite de la méthode send(request:onFailure: onSuccess:).
  • request(_:didFailLoadWithError:) : la requête n’a pas pu être traitée. Le délégué reçoit un message d'erreur. Dans la méthode send(request:onFailure:onSuccess:) n’étant pas associée au délégué, cette erreur serait gérée dans la closure onFailure.
  • requestDidCancelLoad(_:) : la requête a été annulée par un facteur externe, par exemple l’intervention de l’administrateur, une panne de réseau ou un autre événement inattendu. Le délégué ne reçoit aucune valeur de retour. Dans la méthode send(request:onFailure:onSuccess:) n’étant pas associée au délégué, cet échec serait géré dans la closure onFailure.
  • requestDidTimeout(_:) : le serveur Salesforce n’a pas répondu à temps. Le délégué ne reçoit aucune valeur de retour. Dans la méthode send(request:onFailure:onSuccess:) n’étant pas associée au délégué, cet échec serait géré dans la closure onFailure.

Le kit de développement mobile fournit des réponses de réussite au rappel request(_:didLoadResponse:). Si vous vous demandez comment décoder la réponse du réseau, ne vous inquiétez pas. Par défaut Mobile SDK met en forme la réponse en tant que JSON convivial dans un objet de dictionnaire. Ce dictionnaire contient une clé « records » dont la valeur est un tableau d’enregistrements Salesforce. Les conditions d’erreur, d’annulation et d’expiration sont chacune traitées par leurs propres gestionnaires, ce qui facilite la mise en œuvre d’actions spécifiques en fonction des types d’échecs.

Et voilà, la boucle est bouclée. Nous avons initialisé l’application, connecté un utilisateur, émis une requête REST et affiché la réponse REST. L’application est maintenant au repos, car elle ne sait rien faire d’autre. Développons un peu votre application en ajoutant la prise en charge de quelques interactions des utilisateurs, par exemple le balayage vers la gauche pour supprimer.