In summer ’13 salesforce introduced a new set of API to control organization object like Apex class, Apex Trigger, TraceFlag, Visualforce Pages and other components from outside the organization. Tooling API allows to access coverage for Apex class and Apex trigger. Managing custom objects and anonymous execution of code and access debug logs from organization. Tooling API provides bothREST and SOAP API interface to access its features. Tooling API provides set of objects accessible from RESP API and SOAP API. It is just like SOAP API and REST API with a difference of endpoint only and selected set of objects available through it.Below is given Apex code example to create, update and delete operation on apex class. Which will answer, How to use Tooling API? How to create Apex Trigger/Apex Class using Tooling API and How to update these? and various other useful features.
Before working with Tooling API object first create some generic methods which will used throughout the class e.g creating a http request.
Here we created to methods to send request and receive response from Tooling API.
In below example “UserInfo.getSessionId()” will be used to remove confusion and maintain code simplicity.
In endpoint url “ApexClass” is added because we are working on ApexClass object to create a new class. By executing method a new Apex class named “NewApexClass1” will be created in organization and response will be like {“id”:”01p900000039N0vAAE”,”success”:true,”errors”:[]} where in json id is “NewApexClass1” id so that we can perform other operation targeting this id.
To delete a apex class or some other component only DELETE request is need to do by passing component object’s id. If request is successful then Status code 204 will be received and Apex class will be deleted from organization.
Query Tooling Objects:
This will result a JSON of Apex class named “NewApexClass1” with id and name and some other details. There are two fields in JSON because query was about two fields only.
Response will be like:
{
"size":1,"totalSize":1,"done":true,"records":[{
"attributes":{
"type":"ApexClass","url":"/services/data/v28.0/tooling/sobjects/ApexClass/01p900000039N0vAAE"
}
,"Id":"01p900000039N0vAAE","Name":"NewApexClass1"
}
],"queryLocator":null,"entityTypeName":"ApexClass"
}
Describing an individual Tooling object record:
public void accessApexClass()
{
HttpRequest req = createHttpRequest(endpoint+'/sobjects/ApexClass/'+oid,'GET');
getResponse(req));
}
This will result full metadata of Apex class in json format which id (oid) is passed with endpoint url.
Update a Apex class:
To update a apex class involves some more steps then steps we required above. Apex class can be update by ApexClassMember Object and by same way ApexTrigger are updated by ApexTriggerMember and so on.
Steps to update are:
– First we need to create MetadataContainer object ex:
public void createMetadataContainer()
{
HttpRequest req = createHttpRequest(endpoint+'/sobjects/MetadataContainer','POST');
req.setBody('{"Name":"ApexContainer"}');
String response = getResponse(req);
Map<String,Object> rmp = (Map<String,Object>)JSON.deserializeuntyped(response);
String cid = (String)rmp.get('id'); // used to save containerId
}
Store the MetadaContainer id because it will be required in ApexClassMember which is used to hold ApexClassMember, ApexTriggerMember etc.
– After this we need to create ApexClassMember object if we want to update ApexClass. If we want to update Apex Trigger then we need to create ApexTriggerMember. Here is example to create Apex Class so ApexClassMember will be created by:
// mid: MetadaContainserId
// axid: apexclass Id
// classBody: Apex class body (updated)
public void createApexClassMember(String mid, String axid, String classBody)
{
HttpRequest req = createHttpRequest(endpoint+'/sobjects/ApexClassMember','POST');
req.setBody('{"MetadataContainerId" : "'+mid+'", "ContentEntityId" : "'+axid+'", "Body": "'+classbody+'"}');
String response = getResponse(req);
Map<String,Object> rmp = (Map<String,Object>)JSON.deserializeuntyped(response);
String apmid = (String)rmp.get('id'); // Store ApexClassMember Id
}
ApexClassMember require 3 parameters, MetadatacontainerId, ApexClass id (which is created previously) as ContentEntityId and full body of class as string which is updated. Sending request by above code will provide newly created ApexClassMember Id. This should be store in some variable as it will require in next step. Till now this class is not updated.
To update a class ContainerAsyncRequest object is used. It compile and deploy the code and provide status of code. Is code deployed or has some problem and what is the problem. ContainerAsyncRequest object can be created by:
public void createContainerAsyncRequest(String mid)
{
HttpRequest req = createHttpRequest(endpoint+'/sobjects/containerAsyncRequest','POST');
req.setBody('{"MetadataContainerId" : "'+mid+'", "isCheckOnly": "false"}');
String response = getResponse(req);
Map<String,Object> rmp = (Map<String,Object>)JSON.deserializeuntyped(response);
carid = (String)rmp.get('id');
}
It return the id by this status of deployed code can be checked as:
public void getContainerAsyncRequestStatus()
{
HttpRequest req = createHttpRequest(endpoint+'/sobjects/containerAsyncRequest/'+carid,'GET');
String responseJson = getResponse(req));
}
In response to this it provide updated class detail including error. If class deployed successfully error message is null.
{
"attributes":{
"type":"ContainerAsyncRequest",
"url":"/services/data/v28.0/tooling/sobjects/ContainerAsyncRequest/1dr90000000EKSBAA4"
}
,"Id":"1dr90000000EKSBAA4","IsDeleted":false,
"CreatedDate":"2013-09-08T14:32:30.000+0000","CreatedById":"00590000001CfQjAAK",
"LastModifiedDate":"2013-09-08T14:32:30.000+0000","LastModifiedById":"00590000001CfQjAAK",
"SystemModstamp":"2013-09-08T14:32:30.000+0000","MetadataContainerId":"1dc9000000009tXAAQ",
"MetadataContainerMemberId":null,"ErrorMsg":null,
"CompilerErrors":null,"IsRunTests":false,
"State":"Queued","IsCheckOnly":false
}
Same way ApexTrigger can be created using ApexTriggerMember.
Execute Anonymous:
Executing the Apex code
anonymously will available from API version 29.0 or later in Tooling
API sp calling it will result a error “requested resource doesn’t
exist”.
These are the some basic implementation of
Tooling API. Which may help in how Tooling api is used to create
objects.
There are still many things to explore about
tooling api so this post is not completed. In next few days there will
be sure new updates about tooling api.