Andy in the Cloud

From BBC Basic to Force.com and beyond…

192 thoughts on “Introduction to calling the Metadata API from Apex

  1. Pingback: Failing to update picklist on task object via metadata API | DL-UAT

  2. Hello Guys,

    I try to access read the PageLayout using the latest Metadata API i.e 33, I can read all other metadata excepting Layouts.

    Has any face the same problem.

    Thanks!

  3. Andy, that’s indeed brilliant. Awesome stuff. However, I do have one question. Actually, the requirement is to sync two Objects in Salesforce, not only the data but the Metadata too. Let’s say there are two Objects, A and B. If a field is added or deleted in A, the same should reflect in B. Could you please suggest in detail how can I use your metadata api to achieve such functionality???

    • Thanks! There are a lot of examples for this in the metadataserviceexamples class you can use as a basis, then also look at my sobjectdataloader repo for the data side. I am afraid I just don’t have time to go into detail in this with you, sorry. Happy if you want to ask some hi level questions after having a look at the above.

  4. Hi Andy,
    This is very great and helpful API and I’ve a query about retrieving layout metadata. Is there a way I can retrieve all the fields on a specific layout provided the recordType?


    Bilal

  5. Hi Andy,

    I was stuck on a point I have a code which is working fine for retrieve the folder info of an org.

    MetadataService.MetadataPort service = new MetadataService.MetadataPort();
    List queries = new List();
    service.SessionHeader = new MetadataService.SessionHeader_element();
    service.SessionHeader.sessionId = UserInfo.getSessionId();
    MetadataService.ListMetadataQuery queryDocumentFolder = new MetadataService.ListMetadataQuery();
    queryDocumentFolder.type_x = ‘DocumentFolder’;
    queries.add(queryDocumentFolder);
    system.debug(‘========queries=====’+queries);
    MetadataService.FileProperties[] fileProperties = service.listMetadata(queries, 30);
    system.debug(‘========fileProperties=====’+fileProperties);
    List folderNames = new List();
    for(MetadataService.FileProperties fileProperty : fileProperties)
    folderNames.add(fileProperty.fileName.replace(‘documents/’, ”));
    system.debug(‘========queries=====’+queries);

    Now I want to make it generic so in the line “queryDocumentFolder.type_x = ‘DocumentFolder’;” instead of DocumentFolder if I pass “ApexClass” it should return all the Apex class of that org same for other component.
    Currently when I am trying to do this I am facing the exception can you please help me to come out of it?

    Thanks in Advance.

    Abhishek

    • Sorry hard to help if you have to given me the exception your getting. However you may also like to know you can use Soql to query apex classes, just query the ApexClass object. Hope this help, if you want to proceed with Metadata API you will have to give me some more insight as to the exception message you have?

  6. The “create” method does not exist in the MetadataService.cls. Could you please update your example, or provide another example on how to use the Metadata API to create objects such as Workflow Rules using async methods?

  7. Thanks for posting this discussion. I would like to know How to get field Description from object metadata getDescription() ?? Thank you.

  8. Hi guys
    I need to pull lastModifiedDate for RecordType.
    Is this not supported by MetadataService?

    Workbench shows this information for every record type, also official Metadata API listing all the record types shows this.

    Any suggestions or do I need to make official Metadata API call and pull huge amout of RTs?

    • It should be a direct wrapper. Can you raise an issue on the GitHub site with a screenshot of what your seeing elsewhere in the docs and I will try to find it for you. Thanks.

      • I may have not described the case at hand clearly enough 🙂

        So, I’m pulling Record Types using readMetadata(‘RecordType’, ), but there is no info on lastModifiedDate.
        LastModifiedDate is included in listMetada(, ), which I guess is used by workbench and is indeed available in MetadataService, but this pulls huge amount of data in my org (over 600 RTs).

        I was wondering if there is a way to pull lastModifiedDate for RTs without querying all of them.
        Probably not, as my understanding is that lastModifiedDate is a property of a file holding metadata, not of specific metadata as such.

        Background requirement is to get picklist values for different record types, but in a web service for mobile devices, so time is of the essence. My approach for this is to create some “cache” with the values (sObject), that would be refreshed only if anything changed, thus I need lastModifiedDate for included RTs 🙂

        So my final question is: is there a way to pull lastModifiedDate for RTs without querying all of them?

      • Not via metadada API, have you looked at tooling API?

  9. Nope, not yet. I will look into it, but I’m resistant to including yet another API 🙂

  10. Hi Andrew,

    Thank you for such a fantastic class.
    I just wanted to know like if there is a way to reduce the size of the MetadataService class as it itself consumes around 500000 characters and we all know Salesforce is picky about the character limit.
    Any suggestion would be helpful.

    Warm Regards

    • This has been raised as an idea in the GitHub issues list for sure. And is a good one. Checkout some thoughts on there. Other than simply copy and pasting over what you need until it all compiles, I don’t yet have a tool or automated approach to cutting it down. Sorry.

  11. Hi Andrew,

    I tried to invoke the Metadata api from the Salesforce site but it is throwing an error like “Web service callout failed: WebService returned a SOAP Fault: UNKNOWN_EXCEPTION: Site under construction faultcode=UNKNOWN_EXCEPTION faultactor=” in the debug logs, Can you please help me to fix this

    • Check the code that initialises the end point in the metadataservice class, it might need adjusting for this execution context. Also if your running as guest this will not work as that user does not have API or admin access. For that matter I suspect your general issue is site users won’t either. What you may have to consider is a more advanced approach of using a precaptured oauth token from an admin user in the org and having the code pass that as the session id. However you need to be very very careful with this kind of elevation of privileges. What is it your doing with the metadata API, there are some things now that can be done via soql….

  12. hii…..

    How to create tab using metadata API.

    • Take a look at the examples class in the repo, if there is not one, you can probably figure it out from createObject example and by reviewing advice in my FAQ blog, linked from the readme file.

  13. Hi Andrew,
    I am recently getting readtimeout exception while fetching metadata for profiles. It occurs sometime not always, Could you please help me to fix this?.

    • There is a timeout property on the header where you set the session Id, try increasing this

      • Couldn’t find that property, although i added a line service.timeout_x = 90000; but didn’t work out, am i missing somehting

      • I think that’s the one, might be best to post your current issue on the GitHub repository as an issue, me and or others in FF or the community can view it more easily

      • ahh never mind, it worked like a charm, you are a rockstar as always ^_^

      • Ah wonderful!

  14. I have updated timeout property. Thank you very much.

  15. Hi all i am trying to automate post sandbox refresh activities and to achieve this i need to update email alerts, custom labels, outbound messages as at present we need to do manually one by one as these all are metadata so we can’t do by normal apex. so can you share any sugestions how it can be acheived. as in above examples i have seen creating fields and other stuffs.

  16. Did you already try to create connected app through metadataapi?

  17. Hello Andrew ,
    I tried with this MetadataService.AsyncResult[] results =
    service.create(new List { customField }); but gives me this errorMethod does not exist or incorrect signature: [MetadataService.MetadataPort].create(List). It seems that the create method doesn’t exist in MetadataService class that i just uploaded in my org. Big Thanks

  18. Hi All,

    This was a great discussion.

    I’m looking to retrieve all the metadata components (Objects, Fields, Pagelayouts, Validation Rules, Workflow Rules, Approval Processes) based on Last Modified Date by using Query or any kind of script.

    If anyone have any workaround for this.

    Thanks,
    Anil

    • You might want to look at the Tooling API where you can do soql over some of these metadata type objects, then come back to metadata API and build a package xml file driven by the results and passed to the retrieve API. Or you can stick with tooling API and retrieve what you need, though it only currently has a subset of Metadada types.

  19. Hi Andrew Fawcett,
    how can we enable account teams and chatter and lightning design system through apex code can you help me please.

  20. Thank You for Sharing Andrew Fawcett.
    But here i have to enable those things in other org so where can i provide user name and password,url?
    and also i created on package.xml file how can i deploy to org without using any tool like(eclipse,ant,migration,change set), is there any way to deploy through apex code or any back end process. here you provided MetadataServiceExamples class but am unable to find where you are passing username and password,here you are using MetadataDeployController how can you use ZipData prperty,getPackageXml method i tried to use same code in my org but it is not working.
    if you know anything can you provide that information.

    • The samples work only in the org they are installed in. They use UserInfo.getSessionId. If you want to do the same from one org to anther, you have to obtain an oAuth token (recommended) or login as another user via the Logon API and use the resulting session is (not recommend as you would have to store the target orgs user and password).

      • Hi Andrew,

        I tried replacing UserInfo.getSessionId from access token on another Org. But I’m getting multiple exceptions. But I’m getting INVALID_SESSION_ID exception. Then I tried updating the code as follows.

        MetadataService.MetadataPort service = new MetadataService.MetadataPort(); service.SessionHeader = new MetadataService.SessionHeader_element();

        //service.SessionHeader.sessionId = UserInfo.getSessionId();
        service.SessionHeader.sessionId = clientAccessToken;

        //I tried setting following as the endpoint_x. But was getting separate error
        //service.endpoint_x = ‘https://login.salesforce.com’;

        But then I was getting some other exception of “System.CalloutException: Web service callout failed: Unexpected element. Parser was expecting element ‘http://schemas.xmlsoap.org/soap/envelope/:Envelope’ but found ‘http://www.w3.org/1999/xhtml:html'”

        Appriciate if you can help to figure this out. API versions of my source and target orgs are different as well. Source has 38 while target has 39. Not sure whether this might be the reason.

        Thanks a lot for your support in advanced

      • If looks like your trying to use the client access token? Just checking here, you are using an oAuth token from the user/password or web flow from oAuth? You cannot use the static client or secret id given when you setup the connected app. If you are using it. It looks like there is some unmarshalling issue. Run your code from dev console and review the debug log. You will be able to see the actual xml response returned this way. Hope this helps.

      • Many Thanks for the response! I’m using username/password to get access token. The issue i had was with remote site settings. It was pointed to the current instance. So i have changed it to target instance and it worked fine. Moving forward I need to use your solution in my source org as well as the target org. So what’s your suggestion on that?

      • For the source org you can use the running users session id so long as they have access to the API. If not you can have the admin go through the flow and store the oAuth token to be used by the code running on behalf of other users. Obviously use this approach with care

  21. Andrew,

    Need some help. I am trying to get details on profiles in my org using the API.

    I am getting a time out on getting any profile back from the API using this code
    (MetadataService.Profile) service.readMetadata(‘Profile’,new String[] { profn }).getRecords()[0]

    This call always times out, even if I turn up the timeout_x to 90000 so that it exceeds 120 seconds max on call outs and then errors out.

    Note in the above call out the variable profn is equal to a Profle Name that I got back from a call to service.listMetadata(quer, vers) where the type=’Profile’.

  22. Hi Andrew,

    Thanks for sharing such a great API.
    I am trying to deploy selected metadata to my destination org.
    My question is how can i create a zip out of the selected components to pass it as a parameter to deploy() call.

    Please suggest and thanks in advance.

  23. Hi, I am new to Sales Force so this might be a stupid question, but how can I import the .cls file into my org so that all those classes are available?

    • No worries. You can use many tools, if your familiar with command line, Google search for Salesforce Migration Toolkit

    • You can click the Deploy to Salesforce button on the readme file. This is not a Salesforce tool though. Others are Force.com IDE and also Developer Console

      • How would I import using the Developer Console? Again, many thanks, I am a bit new to this.

      • It depends if you only want a few classes, the key ones are metadataservice.cls and metadataservicetest.cls, then copy and paste is best. If it’s the whole repo it’s the Deploy to Salesforce button, or if you prefer to download the repo try the Salesforce Migration Toolkit I mentioned.

      • Got it, that clarified everything! Thank you very much for your help and this awesome wrapper!

  24. Hi, this may be a dumb question, but I am quite new to Salesforce. Could you please tell me how to use the .cls file? Do I have to import it into my SF org somehow? How do I make the classes contained in it available to my apex code in my org?

  25. Hi i am new in Salesforce i am try to delete the apex class in visual force page .. i am getting error, Compile Error: DML not allowed on ApexClass at line . please give any idea to delete the apex class in production using VF page

    • Sorry deleting apex code programmatically in apex directly via do is not supported by the platform.

      You could do this via the Metadada API, this is a WebService api so a http callout is needed. Also you need to use the deploy API operation. If you checkout my flow factory or declarative rollup summary tool in GitHub you can see examples. Also the apex Metadata API wrapper GitHub repo has a deploy example controller you can see.

  26. Hi Andrew,

    I want to update description of bulk custom fields (500 fields) at a time across multiple objects. Do we have any approach to do this?. Could you please provide me sample code for this.

    I know how to fetch the metadata details of custom fields by using Tooling API. From that, I could not able to do an update operation.

    Please check and let us know best approach to do this.

    Thanks,
    Anil

    • My best bet would be to use the Metadada API deploy operation, you can see an example in the deploy controller class and also by studying the deploy api documentation. You would need to include in the package sent to the deploy method .object files with only fields in and description, should should be enough, you can test this via a the ant tool perhaps before wasting time on coding. See the Salesforce migration toolkit for ant usage. Sorry I don’t have a ready made example for you.

  27. can we get all test classes and test methods from one particular project using tooling api then how ?

    • There is no concept of a project in the tooling API only the idea of workspace you set up by making other API calls. I have not kept up with tooling API calls, but it is possible there is an API to get this information since many ide’s provide this ui to select them. If not you will have to parse the apex code classes yourself for this. I just spent a few moments looking at the tooling API docs and didn’t see anything. You might find an answer by looking at code from IDE like MavensMate perhaps, i believe it’s code is open source? Good luck!

  28. Andrew,

    Really appreciate that you have taken the time to build this and are continuing to support it. I’m looking at using your wrapper in an isv package to dynamically add Salesforce’s url.

    Do you happen to know if this would pass the security review process?

    Thanks,
    Brian

    • If you use the component to prompt the admin to approve the connection with the Metadada API they appear to be accepting it. I have seen in the chatter group for the security review team them reference my post outlining this approach to setting up the remote site which allows the comms to work. I assume this is what you mean by “add Salesforce’s url” ?

  29. Hi Andrew Fawcett,

    Are we able to modify the metadata for a custom permission set, for example I am able to create a permission set but I would also like to enable a few check boxes under the System Permission. Like ViewEncryptedData. I would like to do this all with apex code but I couldn’t find anything, I noticed that the metadata has access to it.

    ConfigSettings
    false

    EnabledChatter
    false

    Permission Set that allows the user to Manage Encryption Keys & View Encrypted Data
    Manage Encryption
    Salesforce

    true
    ManageEncryptionKeys

    true
    ViewEncryptedData

  30. Hi Andrew.

    I am battling to get a test mock class implemented for service.readMetadata on a page layout. The actual class is working fine, it is just the mock test that keeps failing with a System.NullPointerException: Attempt to de-reference a null object at the point where I do the readMetadata call. Any help would be greatly appreciated.

    Thanks
    Rudolf.

  31. how to get list of sharing setting and sharing rules in salesforce using metadata api?

  32. Hi, below code is giving me an exception, any idea? i have the remote site settings and i am on Spring17 release.

    Exception:

    System.CalloutException: Web service callout failed: WebService returned a SOAP Fault: Must specify a {http://www.w3.org/2001/XMLSchema-instance}type attribute value for the {http://soap.sforce.com/2006/04/metadata}metadata element faultcode=soapenv:Client faultactor=

    Code:

    system.debug(‘printing ‘+URL.getSalesforceBaseUrl());
    MetadataService.MetadataPort service = new MetadataService.MetadataPort();
    service.SessionHeader = new MetadataService.SessionHeader_element();
    service.SessionHeader.sessionId = UserInfo.getSessionId();
    MetadataService.DuplicateRule customObject = new MetadataService.DuplicateRule();
    customObject.actionOnInsert=’allow’;
    customObject.actionOnUpdate=’allow’;
    customObject.isActive=true;
    customObject.masterLabel=’Main Label’;
    customObject.sortOrder=3;
    customObject.securityOption=’EnforceSharingRules’;
    string [] insertOperations = new string[]{‘Report’};
    string [] updateOperations = new string[]{‘Report’};

    MetadataService.SaveResult[] sr = service.createMetadata(new MetadataService.Metadata[]{customObject});

    • This could be a bug witb the wrapper code not supporting the more complex sharing metadata types. Can you post an issue on the GitHub repo please

  33. Hi Andrew,

    This is impressive. I’m trying to access metadata (Apex classes,VF pages,components,WF rules etc…) on Org B from Org A. I have the access token (retrieved via oAuth) to Org B. Can you use the same methodology to access them?

  34. MetadataService.MetadataPort isn’t found in the MetadataService WSDL. I am actually using C# to set field permissions on a salesforce object.

  35. Hi Andrew Fawcett,

    I am struggling to write an apex code to add new values to a standard picklist field, Can you please share some sample

  36. Hi People,

    Can anyone share apex code sample to add new values to a standard picklist field as a metadata service

  37. Could you please tell me if it is possible to install a managed package from app exchange also utilizing the metadata api?

  38. Hi Andrew,

    Thank you for sharing info on the Metadata api calls from Apex. I am trying to build a SandboxPostCopy script so that it can automate some of the post refresh activities. One of the setting I am trying to update is the remote site settings endpoints.

    After looking into some salesforce docs and online resources, I see that Metadata API is the only way to update RemoteSiteSettings. To access metadata api, I will need to configure the instance url as an endpoint which again requires accessing metadata api. Is there any other way to update the remote site settings through apex from the post copy script. Thanks in advance!

    • This is a catch for sure. Do you find your sandbox is always spinning up on the same instance? If so add this to your production org remote sites. If not, you can deploy my domain to get a fixed URL.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s