Running Apex Code through ExecuteAnonymous API

ForceDotCom Sep 10, 2015

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.

  1. Apex API is available through SOAP protocol.
  2. Tooling API is available through SOAP as well as REST.

Note: For SOAP, You can generate WSDLs from API section of Salesforce.

WSDLs

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:

  1. 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.

  2. Run your executeAnonymous call through API.

  3. 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
    
  4. After getting Id, We need to make an another call for raw logs.

     Endpoint: /services/data/v29.0/sobjects/ApexLog/07L9000004qMsoiEAC/Body
     Method: GET
    
  5. (Optional) Remove trace flags from visibility.

If anyone has any questions about it, I would be glad to help!

Related Tags:

ForceDotCom   API   SOAP   REST   Salesforce