top of page
TrueLines_grandient_1_4x_edited.png
  • fabricefontenoy

L'API Bulk 2.0 de Salesforce

Vous avez besoin d'envoyer plusieurs milliers ou millions d'enregistrements à Salesforce de façon automatisée ?


Vous pouvez bien sûr utiliser le Data Loader en ligne de commande mais ce n'est disponible que sur Windows, ce n'est pas si simple à mettre en place et comment vous faites si vous voulez l'appeler directement depuis un programme tierce ?


L'idéal serait de pouvoir envoyer de la donnée en masse via une API, nan ?


Et ben ça tombe bien ! L'API Bulk est faite pour ça !


Alors comment ça marche ? 🤔



La procédure d'envoi peut se découper en 4 étapes :

  • L'authentification

  • La création d'un job

  • La soumission de la donnée à ingérer

  • La validation du job


Et nous pouvons également ajouter 2 étapes supplémentaires :

  • La récupération du statut du job pour savoir s'il s'est bien déroulé

  • La revocation du token si vous n'avez pas d'autres opérations à effectuer juste après


Dans cet article, je vous propose de voir chacune de ces étapes sur un exemple très simple.


Allez c'est parti 👇



L'authentification


Pour pouvoir s'authentifier à l'API Bulk, il faut opérer de la même manière que pour l'API standard, à savoir créer une App Connectée et récupérer ses credentials (id et secret client).


Pensez également à bien attacher un utilisateur avec les droits d'accès minimum. Pour plus de détails sur ce point, je vous invite à aller voir notre article.


Une fois l'App Connectée bien configurée, vous devez appeler le endpoint suivant pour récupérer un token (ex. avec curl) :

curl --post302 -L --request POST 'https://<url de votre org>/services/oauth2/token'
--header 'Content-Type: application/x-www-form-urlencoded' -d @auth.txt

Où auth.txt contient :

grant_type=client_credentials&client_id=<votre id>&client_secret=<votre secret>

Et vous récupèrerez le token sous cette forme :

{
    "access_token": "<TOKEN>",
    "signature": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "scope": "openid api",
    "instance_url": "https://<url de votre org>",
    "id": "https://login.salesforce.com/id/00D060000010KUOEA2/0050600000HBeA0AAL",
    "token_type": "Bearer",
    "issued_at": "1708346501784"
}

N.B. : Comme Salesforce effectue des redirections d'URL, pensez bien à ajouter les options -L et --post302 pour que les entêtes soient bien redirigées également. Et pour les commandes curl suivantes, il faudra remplacer l'option -L par --location-trusted pour que le token soit également redirigé.



Création du job


La création du job permet d'indiquer à l'API ce qu'on s'apprête à lui envoyer. On va lui spécifier le type de contenu, le type d'opération, l'objet destination, etc.


Pour la suite, nous allons considérer que l'on veuille mettre à jour en masse les enregistrements d'un objet personnalisé Bulk_Info__c. Assurez-vous donc bien que l'utilisateur attaché à l'app connectée a bien les droits nécessaires sur cet objet.


Dans notre cas, nous voulons effectuer une opération d'upsert (insert or update) via le format CSV en identifiant les enregistrements par id externe External_ID__c (pour les updates). Et on va également lui indiquer le type de retour à la ligne sur notre format CSV, ainsi que le délimiteur.


Et pour cela, on va appeler le endpoint suivant (Ex. avec curl) :

curl --post302 --location-trusted -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' --request POST 'https://<votre org>/services/data/v58.0/jobs/ingest' -d '{
  "object":"Bulk_Info__c",
  "contentType":"CSV",
  "operation":"upsert",
  "lineEnding": "LF",
  "externalIdFieldName": "External_ID__c",
  "columnDelimiter": "COMMA"
}'

Ce qui nous renverra une réponse ressemblant à ça :

{
    "id": "7500600000iTXnJAAW",
    "operation": "upsert",
    "object": "Bulk_Info__c",
    "createdById": "0050600000HBeA0AAL",
    "createdDate": "2024-02-19T16:08:40.000+0000",
    "systemModstamp": "2024-02-19T16:08:40.000+0000",
    "state": "Open",
    "externalIdFieldName": "External_ID__c",
    "concurrencyMode": "Parallel",
    "contentType": "CSV",
    "apiVersion": 58.0,
    "contentUrl": "services/data/v58.0/jobs/ingest/7500600000iTXnJAAW/batches",
    "lineEnding": "LF",
    "columnDelimiter": "COMMA"
}

À cette étape, il vous faudra récupérer l'id du job retourné, à savoir 7500600000iTXnJAAW dans notre cas. Cet Id nous servira pour les commandes suivantes.



La soumission


Maintenant que notre job est créé, on va pouvoir lui donner à manger 🍔


On va alors préparer le fichier CSV que l'on veut lui envoyer. Pour l'exemple, on a écrit un fichier très simple de 3000 lignes qui va remplir 2 champs de notre objet Bulk_Info__c. La première ligne du fichier décrit les noms API des champs à remplir et ensuite, chaque ligne correspond à un enregistrement.

Test__c,External_ID__c
TEST_1,1
TEST_2,2
TEST_3,3
TEST_4,4
TEST_5,5
TEST_6,6
TEST_7,7
TEST_8,8
TEST_9,9
TEST_10,10
TEST_11,11
TEST_12,12
TEST_13,13
TEST_14,14
TEST_15,15
TEST_16,16
TEST_17,17
...

Et pour lui envoyer, il suffit d'appeler le endpoint suivant (Ex. avec curl) :

curl --post302 --location-trusted -H 'Content-Type: text/csv' -H 'Authorization: Bearer <TOKEN>' --request PUT 'https://<votre org>/services/data/v58.0/jobs/ingest/7500600000iTXnJAAW/batches/' --data-binary @Bulk_API.csv

Vous recevrez alors un code HTTP 201 avec un corps de réponse vide.


À ce stade, la donnée est définie pour le téléversement mais aucune donnée n'est encore chargée et créé dans Salesforce. Pour cela, il faut finaliser l'envoi en déclarant la soumission comme terminée.


N.B. : Attention, il faut bien mettre --data-binary et pas juste --data car cette dernière option retire les retours à la ligne.



La validation


L'opération précédente peut-être répétée plusieurs fois pour soumettre plusieurs lots de données par exemple provenant de sources différentes.


Une fois l'ensemble des fichiers envoyés, la commande suivante permet de valider l'opération et de démarrer le chargement :

curl --post302 --location-trusted -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' --request PATCH 'https://<votre org>/services/data/v58.0/jobs/ingest/7500600000iTXnJAAW/' -d '{"state":"UploadComplete"}'

Cette commande retournera une réponse semblable à :

{
  "id": "7500600000iTXnJAAW",
  "operation": "upsert",
  "object": "Bulk_Info__c",
  "createdById": "0050600000HBXrAAAX",
  "createdDate": "2024-02-19T22:02:27.000+0000",
  "systemModstamp": "2024-02-19T22:02:27.000+0000",
  "state": "UploadComplete",
  "externalIdFieldName": "External_ID__c",
  "concurrencyMode": "Parallel",
  "contentType": "CSV",
  "apiVersion": 58
}

À ce stade, le job est soumis mais pas forcément encore exécuté. La grande majorité du temps, il est exécuté instantanément mais si beaucoup de jobs sont déjà en court d'exécution ou ont déjà été soumis, il se peut que votre job soit mis en attente.



Récupération du statut


Pour savoir si votre job a bien été exécuté et si tous vos enregistrements ont bien été traités, vous pouvez soit aller sur la page admin des jobs de chargement en masse (Bulk Data Load Jobs), soit exécuter la commande suivante pour récupérer directement le statut de votre job :

curl --post302 --location-trusted -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' --request GET 'https://<votre org>/services/data/v58.0/jobs/ingest/7500600000iTXnJAAW/'

Et vous obtiendrez alors le détail du statut de votre job avec notamment le statut JobComplete et le nombre d'enregistrements traités (3000 ici)

{
  "id": "7500600000iTXnJAAW",
  "operation": "upsert",
  "object": "Bulk_Info__c",
  "createdById": "0050600000HBXrAAAX",
  "createdDate": "2024-02-19T22:02:27.000+0000",
  "systemModstamp": "2024-02-19T22:04:14.000+0000",
  "state": "JobComplete",
  "externalIdFieldName": "External_ID__c",
  "concurrencyMode": "Parallel",
  "contentType": "CSV",
  "apiVersion": 58,
  "jobType": "V2Ingest",
  "lineEnding": "LF",
  "columnDelimiter": "COMMA",
  "numberRecordsProcessed": 3000,
  "numberRecordsFailed": 0,
  "retries": 0,
  "totalProcessingTime": 4661,
  "apiActiveProcessingTime": 4040,
  "apexProcessingTime": 0
}

Révocation du token


Une fois que vous avez effectué tous les appels API que souhaitiez faire, il est recommandé de révoquer le token pour éviter toute utilisation si celui-ci a été divulgué.


Pour cela, il suffit d'appeler le endpoint suivant :

curl --post302 -L --request POST 'https://<votre org>/services/oauth2/revoke' --header 'Content-Type: application/x-www-form-urlencoded' -d 'token=<TOKEN>'

Et vous obtiendrez normalement une réponse 200 avec un corps de réponse vide.



Conclusion


Si vous avez l'habitude d'utiliser l'API standard Salesforce, vous pouvez trouver l'API Bulk un peu plus compliquée et c'est sûr qu'elle comporte des étapes supplémentaires.

Mais si vous devez envoyer un grand nombre d'enregistrements de façon automatisée, c'est certainement la solution à mettre en place.


D'ailleurs Salesforce conseille d'utiliser cette API plutôt que l'API standard à partir d'un envoi de plus 2 000 enregistrements. Mais les limites sont fixées à 150 millions d'enregistrement par période de 24 heures !






71 vues
bottom of page