So I was recently trying to get a list of LWC components and found that the Object was name LightningComponentBundle. Now if you want to see the components you could use the Developer Console, select the Tooling API check box and issue the following query

SELECT ApiVersion,CreatedDate,LastModifiedDate, DeveloperName,MasterLabel,NamespacePrefix 
FROM LightningComponentBundle

This is what it would look like in the Developer Console.

Now this looks simple enough but if you try to run tooling API queries in some cases you won’t be able to access the object. To get around this we can use the Tooling API. Consider the following code for executing a query using the tooling API REST callouts.

HttpRequest req = new HttpRequest();
req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID()); //Get user Session ID
req.setHeader('Content-Type', 'application/json');
String SFdomainUrl=URL.getSalesforceBaseUrl().toExternalForm();
String query='Select+Id,ApiVersion,CreatedDate,LastModifiedDate,MasterLabel+from+LightningComponentBundle+Limit+50';

req.setEndpoint(SFdomainUrl + '/services/data/v45.0/tooling/query/?q=' + query);

req.setMethod('GET');

Http h = new Http();
HttpResponse response = h.send(req);

system.debug(response.getBody());

Map<String, Object> payload1 = (Map<String, Object>)JSON.deserializeUntyped(response.getBody());
system.debug('List of Records ==>' + payload1.get('records'));
List<Object> items = (List<Object>)payload1.get('records');
    
for (Object item : items) 
{    
	Map<String, Object> i = (Map<String, Object>)item;    
	
	DateTime dt = (DateTime)Json.deserialize('"'+i.get('LastModifiedDate')+'"', DateTime.class);
	Date lastModified = date.newinstance(dt.year(), dt.month(), dt.day());

	String label = (String)Json.deserialize('"' + i.get('MasterLabel') + '"', String.class);
	System.debug('MasterLabel ==>' + label);
	System.debug('DateTime ==>' + lastModified.format());
}

Couple of points of interest 1) because this is executing in the Salesforce Org just using the SessionId value should authenticate this REST transaction. 2) Always get the Salesforce Domain to make sure you you have the correct domain URL for the tooling call. 3) Make sure you check the version of the Tooling API you want to access (in this case 45.0) as part of the URL.

So when the call is made, the query is executed and the JSON response is sent back. In the response we have an array of records. I cast that to a List<Object> so I can iterate through it. To pull the values I use the JSON.deserialize() call to deserialize the string data for the proper field, and cast it to it’s respective Type.

Pretty nifty eh? But lets say we want to do something more drastic, such as execute an anonymous apex block. The previous code can be modified by changing the endpoint to anonymous?=<code>

HttpRequest req = new HttpRequest();
req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID()); //Get user Session ID
req.setHeader('Content-Type', 'application/json');
String SFdomainUrl = URL.getSalesforceBaseUrl().toExternalForm();

req.setMethod('GET');

Http h = new Http();

String body = 'System.debug(';
body += '\'==> Test\'';
body += ');';


req.setEndpoint(SFdomainUrl + '/services/data/v45.0/tooling/executeAnonymous/?anonymousBody=' + EncodingUtil.urlEncode(body, 'UTF-8'));
Httpresponse response = h.send(req);
system.debug('Anonymous Execute ==>' + response.getBody());

This doesn’t do much but it shows you how to use the Anonymous callout. For true blocks of big code you’d probably want to use the SOAP version as the limitation of REST is the length of the query string.

Which brings us to another example using the SOAP API. To get the SOAP API to work in many cases you need to go to the API and generate the WSDL for import into Java/.NET or whatever language you are using. However, if you’re trying to add the ability to Execute Anonymous code in your current org to a class you can do so by building the XML request and sending it using the POST method.

public String executeAnonymous(String apexString, Boolean enableDebug) 
{
    String result = '';
    if ( apexString != null && apexString.length() > 0 ) {
                 
        Boolean debugEnabled = enableDebug==null?false:enableDebug;
		String SFdomainUrl = URL.getSalesforceBaseUrl().toExternalForm();
		String endPoint = SFdomainUrl + '/services/Soap/s/54.0/'; 
		Http h = new Http();

        HttpRequest req = new HttpRequest(); 

        req.setEndpoint( endpoint );
        req.setHeader( 'User-Agent', 'SFDC Apex Callout Service' ); 
        req.setHeader( 'SOAPAction', '""' );
        req.setHeader( 'Accept', 'text/xml, application/soap+xml' );
        req.setHeader( 'Content-Type', 'text/xml; charset=UTF-8' ); 

        String soapXML = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://soap.sforce.com/2006/08/apex"><soapenv:Header><SessionHeader>'+
                            '<sessionId>'+ UserInfo.getSessionID() +'</sessionId>'+
                            (debugEnabled?'</SessionHeader><DebuggingHeader xmlns="http://soap.sforce.com/2006/08/apex"><categories><category>Apex_code</category><level>Finest</level></categories><debugLevel>Debugonly</debugLevel></DebuggingHeader>':'</SessionHeader>')+
                            '</soapenv:Header><soapenv:Body><executeAnonymous><String>'+apexString+'</String></executeAnonymous></soapenv:Body></soapenv:Envelope>';
        System.debug( LoggingLevel.WARN, 'SOAP XML: ' +  EncodingUtil.urlEncode( soapXML, 'UTF-8' ) );
        req.setBody(soapXML);
        req.setMethod( 'POST' );

        HttpResponse res = h.send(req); 
        result = res.getBody();
        System.debug( LoggingLevel.DEBUG, 'HTTP RESPONSE: ' + res.toString()+ ' '+  res.getBody() );       
        if ( res.getStatusCode() == 500 ) 
		{
            System.debug( LoggingLevel.ERROR, 'HTTP SOAP ERROR: '+res.getBody()==null?'': res.getBody());           
        }        
    }
    return result;
}

While the above code isn’t super pretty it demonstrates how to build the SOAP request and deal with the response. To see it in action you can paste the above code into the Execute Anonymous window in the debugger console and append the following 4 lines below at the end of the function declaration to see it in action

String body = 'System.debug(';
body += '\'==> Test\'';
body += ');';

executeAnonymous( body, false ); 

Here are a few links

Check this out: https://github.com/JitendraZaa/Anonymous-Apex-Executer/tree/master/Anonymous%20Apex%20Executer

[contact-form]