[SalesForce] Has anyone, ever, successfully invoked the Metadata API from within Apex

While researching a semi-related question posted here earlier, I dug up some interesting and conflicting information regarding whether it's even possible to use the Metadata API from within Apex. I used to be of the belief that this was strictly forbidden, as others seem to agree with. In a related post a Force.com MVP states:

"You can't callout to any Salesforce web services from within
Salesforce
. You can only callout to external web services."

But looking around I found some hopeful posts along with a more recent post at the Force.com Cookbook which suggests that it should be possible. I've discovered plenty of people who claim that it is possible, though so far I can find absolutely nothing confirming that anyone has actually done this successfully.

For example, from this post:

Yes. You can use Ajax Toolkit to call Metadata API calls, but this
possible only in VisualForce pages not Apex Class.
http://www.salesforce.com/us/developer/docs/ajax/index.htm

So if you (or anyone you know) has done this and can share the details of the process, or at least the steps to achieve a login and then a simple create() from within Apex, please share your results!

Best Answer

it's definitely possible to use CRUD based Metadata API calls in APEX. salesforce to salesforce and even loopback inside the same instance, we tried both. Adam already mentioned that a major part of the functionality is based on zipped metadata packages which cannot be created or unzipped using apex. however you can still create custom fields or objects using the create call which can be pretty useful. The ugly part of this is WSDL2APEX as it does not support schema type extensions but the Metadata WSDL has a super type Metadata that all components inherit from. We tried to modifiy the metadata WSDL and code WSDL2APEX produced but we ended up sending our own SOAP messages. Here's some simple code I just tested that illustrates how APEX can be leveraged to create a new custom object, just paste it into the developer console to test it:

HTTP h = new HTTP();
HTTPRequest req = new HTTPRequest();
req.setMethod('POST');
req.setHeader('Content-Type', 'text/xml');
req.setHeader('SOAPAction', 'create');

String b = '<?xml version="1.0" encoding="UTF-8"?>';
b += '<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">';
b += '<soapenv:Header>';
b += '<ns1:SessionHeader soapenv:mustUnderstand="0" xmlns:ns1="http://soap.sforce.com/2006/04/metadata">';
b += '<ns1:sessionId>' + UserInfo.getSessionId() + '</ns1:sessionId>';
b += '</ns1:SessionHeader>';
b += '</soapenv:Header>';
b += '<soapenv:Body>';
b += '<create xmlns="http://soap.sforce.com/2006/04/metadata">';
b += '<metadata xsi:type="ns2:CustomObject" xmlns:ns2="http://soap.sforce.com/2006/04/metadata">';
b += '<fullName>sample__c</fullName>';
b += '<deploymentStatus>Deployed</deploymentStatus>';
b += '<description>created by the Metadata API</description>';
b += '<enableActivities>true</enableActivities>';
b += '<label>sample Object</label>';
b += '<nameField>';
b += '<displayFormat>AN-{0000}</displayFormat>';
b += '<label>sample__c Name</label>';
b += '<type>AutoNumber</type>';
b += '</nameField>';
b += '<pluralLabel>sample Objects</pluralLabel>';
b += '<sharingModel>ReadWrite</sharingModel>';
b += '</metadata>';
b += '</create>';
b += '</soapenv:Body>';
b += '</soapenv:Envelope>';

req.setBody(b);
req.setCompressed(false);
req.setEndpoint('https://na12-api.salesforce.com/services/Soap/m/25.0');
HTTPResponse resp = h.send(req);
System.debug(resp.getBody());

you probably have to adjust the endpoint to point to your server. Using some Visualforce and a actionPoller component you can develop a nice object builder and even check if the asynchronous object creation was succussful.

Related Topic