Running Apex Code through ExecuteAnonymous API
Hi Friends,
I was working on a POC wherein I need to run apex code through ExecuteAnonymous API like Workbench does. I got stuck on this one as it was not a straight forward task and I spend some time on research so wanna share my research with you guys.
First of all, ExecuteAnonymous call is available through Apex API & Tooling API.
- Apex API is available through SOAP protocol.
- Tooling API is available through SOAP as well as REST.
Note: For SOAP, You can generate WSDLs from API section of Salesforce.
Problem:
Catch over here is whenever you run these requests either through SOAP or REST, We won't get body/raw log for apex code executed. We only get following result:
{
"line" : -1,
"column" : -1,
"compiled" : true,
"success" : true,
"compileProblem" : null,
"exceptionStackTrace" : null,
"exceptionMessage" : null
}
There is no straight forward way in REST API to get the body. For SOAP, We need to add a debugging header in request to get raw log in response.
<apex:DebuggingHeader>
<apex:categories>
<apex:category>Apex_code</apex:category>
<apex:level>FINEST</apex:level>
</apex:categories>
<apex:debugLevel>DETAIL</apex:debugLevel>
</apex:DebuggingHeader>
Full Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:apex="http://soap.sforce.com/2006/08/apex">
<soapenv:Header>
<apex:DebuggingHeader>
<apex:categories>
<apex:category>Apex_code</apex:category>
<apex:level>FINEST</apex:level>
</apex:categories>
<apex:debugLevel>DETAIL</apex:debugLevel>
</apex:DebuggingHeader>
<apex:SessionHeader>
<apex:sessionId>sessionId</apex:sessionId>
</apex:SessionHeader>
</soapenv:Header>
<soapenv:Body>
<apex:executeAnonymous>
<apex:String>System.debug('Hello');</apex:String>
</apex:executeAnonymous>
</soapenv:Body>
</soapenv:Envelope>
Full Response
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://soap.sforce.com/2006/08/apex" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<DebuggingInfo>
<debugLog>34.0 APEX_CODE,FINEST
Execute Anonymous: System.debug('Hello');
01:53:57.042 (42323953)|EXECUTION_STARTED
01:53:57.042 (42336750)|CODE_UNIT_STARTED|[EXTERNAL]|execute_anonymous_apex
01:53:57.042 (42750478)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:1
01:53:57.042 (42867541)|STATEMENT_EXECUTE|[1]
01:53:57.042 (42874614)|STATEMENT_EXECUTE|[1]
01:53:57.042 (42882147)|HEAP_ALLOCATE|[1]|Bytes:5
01:53:57.043 (43033648)|ENTERING_MANAGED_PKG|
01:53:57.043 (43067036)|USER_DEBUG|[1]|DEBUG|Hello
01:53:57.043 (43116911)|CODE_UNIT_FINISHED|execute_anonymous_apex
01:53:57.044 (44702729)|EXECUTION_FINISHED</debugLog>
</DebuggingInfo>
</soapenv:Header>
<soapenv:Body>
<executeAnonymousResponse>
<result>
<column>-1</column>
<compileProblem xsi:nil="true"/>
<compiled>true</compiled>
<exceptionMessage xsi:nil="true"/>
<exceptionStackTrace xsi:nil="true"/>
<line>-1</line>
<success>true</success>
</result>
</executeAnonymousResponse>
</soapenv:Body>
</soapenv:Envelope>
As I mentioned above, there is no straight forward way to do this in REST API. This can be done in 4 Steps:
-
Set Trace Flag : To log logs against your user
Endpoint : /services/data/v34.0/tooling/sobjects/traceFlag Method : POST Post: { "ApexCode": "Finest", "ApexProfiling": "Error", "Callout": "Error", "Database": "Error", "ExpirationDate": "2015-09-11", "TracedEntityId": "00590000000tQBwAAM", "Validation": "Error", "Visualforce": "Error", "Workflow": "Error", "ScopeId": null, "System": "Error" }
To know more about Trace Flag, go through this documentatation.
-
Run your executeAnonymous call through API.
-
Then, We need to make a query to get Id of raw log from ApexLog table. Run below query to get last log from user.
SELECT Id FROM ApexLog WHERE Request = 'API' AND Location = 'Monitoring' AND Operation like '%executeAnonymous%' AND LogUserId='00590000000tQBwAAM' ORDER BY StartTime DESC, Id DESC LIMIT 1
-
After getting Id, We need to make an another call for raw logs.
Endpoint: /services/data/v29.0/sobjects/ApexLog/07L9000004qMsoiEAC/Body Method: GET
-
(Optional) Remove trace flags from visibility.
If anyone has any questions about it, I would be glad to help!