I've been looking online and noticed different ways people are attempting to leverage the Metadata API WSDL through APEX directly (and the issues around consuming the WSDL), but I was curious whether another approach is viable (or will inevitably break) for my scenario.

I'm looking to do a very limited set of things for a managed package that comes with an empty object: Add and Delete fields on that object via Visualforce/Apex. My question is, can I take the generated XML body I would use for those two requests, build it up as a String, ensure that my endpoint is always the same API version (in this case 26.0), and be confident that that XML body will always yield a valid response in the future?

1 Answer 1


Web Services & Apex: The Metadata API is a supported Web Service API, meaning regardless of the client you call it from, as is the goal of SOAP, it is client agnostic. That even includes Apex clients, which actually has reasonably good SOAP support, which is for sure not going anywhere.

That said, in the case of the Metadata WSDL, it requires some coaxing to use the WSDL2Apex tool. To to generate the Apex classes needed to consume this API in a type safe mannor (e.g. no manually building XML requests or parsing responses).

Metadata API from Apex: Take a look at the Apex Metadata API, which is pre-built wrapper around the Metadata API (notes are included if you want to do it manually). It allows you for example to perform the following from Apex/Visualforce.

public static void createObject()
    MetadataService.MetadataPort service = createService();     
    MetadataService.CustomObject customObject = new MetadataService.CustomObject();
    customObject.fullName = 'Test__c';
    customObject.label = 'Test';
    customObject.pluralLabel = 'Tests';
    customObject.nameField = new MetadataService.CustomField();
    customObject.nameField.type_x = 'Text';
    customObject.nameField.label = 'Test Record';
    customObject.deploymentStatus = 'Deployed';
    customObject.sharingModel = 'ReadWrite';
    MetadataService.AsyncResult[] results = service.create(
       new List<MetadataService.Metadata> { customObject });

public static void createField()
    MetadataService.MetadataPort service = createService();     
    MetadataService.CustomField customField = new MetadataService.CustomField();
    customField.fullName = 'Test__c.TestField__c';
    customField.label = 'Test Field';
    customField.type_x = 'Text';
    customField.length = 42;
    MetadataService.AsyncResult[] results = service.create(
       new List<MetadataService.Metadata> { customField });

Metadata API Endpoint and Version Configuration:

The generated MetadataService.MetadataPort contains the following init code with minor tweak to adapt to the current org instance. As you can see it also hard codes the API version. Note that in order to upgrade to 26 or the latest 27 you will need repeat the WSDL2Apex process described here.

    public String endpoint_x;
        // Workaround to platform bug (?) where the following method returns a none HTTPS URL in a Batch Apex context
        URL baseUrl = URL.getSalesforceBaseUrl();
        System.debug('Protocol is ' + baseUrl.getProtocol());
        if(baseUrl.getProtocol() == 'http')
            baseUrl = new URL('https', baseUrl.getHost(), baseUrl.getPort(), baseUrl.getFile()); // Switch to https protocol
        endpoint_x = baseUrl.toExternalForm() + '/services/Soap/m/25.0';

Note: I actually plan to update it over the weekend if you can wait till then. Or if API 25.0 does what you need (which i think it does), your good to go!

Hope this helps!

  • Very interesting work you've done here! So theoretically, whenever you use a type-unsafe string of XML or this custom wrapper, the underlying SOAP calls should have to remain the same for that particular API version. Commented Feb 22, 2013 at 19:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .