Vous êtes développeur ou fonctionnel avec une connaissance technique.
Venez découvrir la puissance de la Tooling API : la boite à outils qui permet de mieux s'approprier vos metadata.
Au cours de cet événement, nous vous présenterons les possibilités de cette API et quelques cas d'utilisation.
A l'issu de la session, vous comprendrez les possibilités et comment débuter avec cette Api
Informations complémentaires :
Profil développeur & fonctionnel ayant des connaissances techniques
pré-requis :
Savoir ce qu'est une API
Comprendre le SOQL
Niveau avancé
Événement virtuel
2. Ceci ne s’applique pas pour tout ce que vous verrez par la suite :
L’intégralité de ce que vous verrez à été fait par un développeur
qui n’est pas un cascadeur,
Donc vous vous pouvez aussi le faire
Aucune org salesforce n’a été blessée ou tuée durant l’ensemble
des phases de développement et de test
2
4. Qui êtes-vous (37 réponses) ?
4
0
2
4
6
8
10
12
14
16
18
20
Administrator Developer Other
Your profile
0
5
10
15
20
25
30
No Yes
Do you know Tooling API ?
0
5
10
15
20
25
30
35
No Yes
Do you use Tooling API ?
5. Metadata API
(SOAP)
Api en bloc
Tooling API (Printemps 2013)
(SOAP/REST/SOQL)
Api granulaire
5
select CreatedById, CreatedBy.Name, CreatedDate, fullname, Id, LastModifiedById, LastModifiedBy.Name,
LastModifiedDate, ManageableState,
Description, ErrorDisplayField, ErrorMessage, ValidationName, Active
from ValidationRule where EntityDefinition.DeveloperName ='Case' and Id='03d3z000000QlbjAAC'
Information communes
Information supplémentaires
6. TOOLING API
1 seule API mais plusieurs usages différents possible
• Recherche en SOQL
• Activation du debug mode
• Exécution des tests et analyse couverture de
code
• Analyse de la structure des classes
• Débogage
• Création/Modification unitaire de config
• Exécution de code anonyme
• Création d’outil générique (génération de
package, etc …)
6
7. Fonction Recherche (1/3)
174 objets exploitables dont 1 objet pivot :
• EntityDefinition : la description de tous les objets salesforce ( si tooling API)
• champs : isSomething (isCustomSetting,isEverCreatable …) , prefix, DeveloperName,DurableId,
qualifiedApiName …
• DeveloperName : nom technique sans __xx
• qualifiedApiName : Nom technique avec __xx (si besoin)
• DurableId : l’id qui sera utilisé majoritairement dans les références au sein de la toolingApi.
Select * from FieldDefinition WHERE EntityDefinitionId ='Account'
7
8. Fonction Recherche (2/3)
• Ce qu’on peut et ne peut pas faire :
• Chercher un custom Label par rapport au contenu possible de la valeur :
select Category ,MasterLabel ,Name ,value from ExternalString where value like '%Test%'
• Chercher les validation rule qui correspondent à un message d’erreur :
select Id,Active,EntityDefinition.DeveloperName ,ErrorDisplayField,ErrorMessage,ValidationName from
ValidationRule where active=true and ErrorMessage like '%changement de statu%'
• Ce qu’on ne peut pas faire en standard :
certains champs ne peuvent etre requete si la requete ne ramène pas une occurrence unique :
fullName, metadata
select id, metadata,fullName from flow KO
select metadata,fullName from flow where id = '3012o000000HJzSAAW' OK
8
9. 9
Methode pour executer une requetes SOQL via la tooling Api :
public static List<Map<String, Object>> getResult(String query){
HttpRequest req = new HttpRequest();
req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
req.setHeader('Content-Type', 'application/json');
req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm()+'/services/data/v47.0/tooling/query/?q='+EncodingUtil.urlEncode(query,'UTF-8'));
req.setMethod('GET');
HttpResponse res = (new Http()).send(req);
Map<String, Object> fieldMap = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
List<Object> recordsMap = (List<Object>)fieldMap.get('records');
List<Map<String, Object>> result = new List<Map<String, Object>> ();
for(Object anObj : recordsMap){
result.add((Map<String, Object>)anObj);
}
return result;
}
Execution d’une requete en apex :
System.debug(ToolingApiUtil.getResult('select Id,Category,Language,MasterLabel,Name,Value from ExternalString order by lastModifieddate desc limit 1’));
Log :
17:59:00:086 USER_DEBUG [16]|DEBUG|({Category=Alerts, Id=10125000001RKQlAAO, Language=en_US, MasterLabel=Feature Not Available,
Name=Feature_Not_Available, Value=This feature is currently unavailable.,
attributes={type=ExternalString, url=/services/data/v47.0/tooling/sobjects/ExternalString/10125000001RKQlAAO}})
Requete soql toolingApi en apex
Penser à cocher la case si vous faites une requête tooling et à la décocher sinon
10. Fonction Recherche (3/3)
L’objet : METADATADEPENDENCY (MetadataComponentId, MetadataComponentName,
RefMetadataComponentId, RefMetadataComponentName, RefMetadataComponentType)
Cet objet permet de déterminer les interdépendances entre les metadata Salesforce. On peut ainsi répondre aux
2 questions :
- De quoi ma metadata dépend :
SELECT MetadataComponentName, RefMetadataComponentType ,RefMetadataComponentName FROM MetadataComponentDependency WHERE MetadataComponentId = '01p25000001zNi5AAE'
- Ou est utilisé ma metadata :
SELECT MetadataComponentName, MetadataComponentType,RefMetadataComponentName FROM MetadataComponentDependency WHERE RefMetadataComponentId = ‘01ID0000000ugBdMAI'
Exemple d’utilisation :
- Ou est utilisé mon champs (apparu avec la spring 2020)
- Pouvoir déterminer les metadata nécessaires pour aliment une scratch org afin de faire des tests
Les requetes sont limités à 2000 records (summer 2020 ,1 000 000 de records en bulk api)
10
13. Fonction creation/update
• Création ou update de metadata
• Exemples d’utilisation :
• Modifier et forcer le recalcul d’un Rollup summary field
• Creation d’une application pour tester des formules
• Création de traceFlag automatisé
• Suppression en masse sans passer par un destructive package
• Etc ….
13
14. Methode pour Créer , Modifier, Supprimer un objet via la tooling Api :
public static void createObject(String type,Map<String,Object> param){
crud(type,param,null,'POST');
}
public static void updateObject(String type,Map<String,Object> param,String idObject){
crud(type,param,idObject,'PATCH');
}
public static void deleteObject(String type,String idObject){
crud(type,null,idObject,'DELETE');
}
public static void crud(String type,Map<String,Object> param,String idObject,String operation){
String endOperation='/';
if(idObject!=null){
endOperation+=idObject;
if(operation=='PATCH'){endOperation+=+'?_HttpMethod=PATCH';operation='POST';}
}
HttpRequest req = new HttpRequest();
req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
req.setHeader('Content-Type', 'application/json');
req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm()+'/services/data/v47.0/tooling/sobjects/'+type+endOperation);
req.setBody(JSON.serialize(param));
req.setMethod(operation);
system.debug((new Http()).send(req));
}
CRUD via la toolingApi en apex (1/2)
15. 15
Creation d’un CustomLabel :
Map<String,Object> externalString = new Map<String,Object>();
externalString.put('Category','test');
externalString.put('MasterLabel','Master Label TA');
externalString.put('Name','NameToolingApi');
externalString.put('Value','value Tooling Api');
ToolingApiUtil.createObject('ExternalString',externalString,null);
Modification :
Map<String,Object> externalStringUpdate = new Map<String,Object>();
externalStringUpdate.put('Category’,new Category');
String idCustomLabel = (String)ToolingApiUtil.getResult('select Id,Category,Language,MasterLabel,Name,Value from ExternalString where Name='NameToolingApi'')[0].get('Id');
ToolingApiUtil.updateObject('ExternalString',externalStringUpdate,idCustomLabel);
Suppression :
String idCustomLabel = (String)ToolingApiUtil.getResult('select Id,Category,Language,MasterLabel,Name,Value from ExternalString where Name='NameToolingApi'')[0].get('Id');
ToolingApiUtil.deleteObject('ExternalString',idCustomLabel);
CRUD via la toolingApi en apex (2/2)
16. Fonction debug log
• L’objet DebugLevel :
• Choix du level pour (ApexCode,ApexProfiling,Callout, etc …)
• L’objet TraceFlag :
• Choix du debugLevel (DebugLevelId)
• Choix de l’entité à tracer (User, Classe,Apex Trigger,Automated Process)
• Date d’expiration de la trace (max 24h00)
Exemple d’utilisation :
- Modifier une trace pour pouvoir logger plus de 24h00 une action spécifique via un batch
- Pouvoir automatiquement tracer un utilisateur lorsqu’on utilise la fonction loginAs
- Pouvoir réécrire complétement l’interface des log à votre convenance
16
18. Fonction TestResult / Code coverage
• L’objet ApexCodeCoverage :
• ApexClassOrTriggerId
• TestMethodName
• NumLinesCovered
• NumLinesUncovered
• Coverage (detail de la couverture ligne par ligne)
Exemple d’utilisation :
- Rechercher avec précisions comment une classe est couverte en vue d’en faciliter le déploiement en l’absence
d’une classe de test correspondante
- Créer une interface de visualisation de la couverture plus flexible que la console
18
21. Fonction execute anonymous/
execution des classes de test
• Pouvoir executer du code Apex à partir d’un simple appel
à un webservice
• Pour voir planifier l’execution de vos classes de test
Exemple d’utilisation :
- Création d’un écran d’execution qui n’affiche que les debug
- Création d’un écran pour afficher le resultat json retournée par une méthode
- Etc …
21
25. Fonction debug
• ApexExecutionOverlayAction :
• ActionScriptType(None,SOQL,Apex) , isDumpingHead,Iteration,Line
• ApexExecutionOverlayResult :
• ApexResult, ClassName, HeapDump, OverlayResultLength,SoqlResult
• Utilisation :
• Permet d’executer du soql, un dump ou même du code apex à chaud
• WARNING : Executer du code apex stop la transaction au moment de
l’execution. Le resultat n’est affiché que dans la log pas dans l’objet result
25
26. Utilisation du debugger avec un requête
Contenu du champs SoqlResult
après utilisation du debugger
28. Coktail party
• Génération autonome de package
• Tooling Api
• Partner Api
• External code
• Un peu de folie
Création automatique
du package avec pour critère :
- date première modification
- date dernière modification
- Filtre par utilisateur ou non
28
29. Quelques liens utiles
L’ensemble des objets manipulables via la tooling Api :
https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/reference_objects_list.htm
Un site qui explique les différents types utilisable pour la metadatadependency:
https://github.com/afawcett/dependencies-sample)
Slack : https://join.slack.com/t/communityfrance/shared_invite/zt-e10uch11-W4rfrk4KrgSZR4tG0vd4PQ
Si vous avez des questions , vous pouvez m’écrire à :
fabrice.challier@littlechaman.com
Editor's Notes
Penser à parler de rest vs soap (meme si c’est un peu technique pour des admin)
Montrer que FileName n’existe pas mais qu’on a accès à d’autre champs --ToolingVsMetadata +workbench
select CreatedById,CreatedBy.Name,CreatedDate,fullname,Id,LastModifiedById,LastModifiedBy.Name,LastModifiedDate,ManageableState,Description,ErrorDisplayField,ErrorMessage,ValidationName,Active from ValidationRule where EntityDefinition.DeveloperName ='Case'
Cette table existe en standard comme en tooling api.Montrer un durableId un developerName et un qualifiedApiName pour un objet custom ->>ToolingApi_EntityDefinition + montrer dans dev console
Chaque objet n’a de visibilité que sur certains type de dépendance ( plus d’infos : https://github.com/afawcett/dependencies-sample)
exemples :
Ou est utilisé mon CustomLabel ira chercher dans : ApexClass,ApexTrigger,VisualForce, Lightning Component Markup, Lightning Component ControllerOu est utilisé mon Flow ira chercher dans : ProcessBuilder,Apex,Lightning actions, lightning page, flow
Etc …
Penser à insister sur le fait que les admin peuvent se focaliser sur le besoin « métier » et sur l’émergence d’une solution technique
AP24MAJCase : très bon use case
Case aCase = new Case();
insert aCase;
system.debug(aCase.id);
aCase.Id=null;
update aCase;
Full
LWC383InfosSurLT.getInfos('5002o00002JMHXbAAP')
fabrice fabrice challier / FormulaTesterUtil / 1 ou 2 /153
Soql : select testVR__c from Case where id ='500P0000008WunQIAS’