16

Question

Is it possible to create or update a NamedCredential from within Apex?

Investigation

I looked into available options, and it seems the SOAP API only supports the describeSObjects(), query(), and retrieve() operations. The Tooling API doesn't seem to support the object at all. But the Metadata API does!

Let's play around with some scripts in Execute Anonymous and see what we can do with the Apex Wrapper Salesforce Metadata API.

Working with the Metadata API

Helper Methods

Here are some bare-bones helper methods pulled out of the MetadataServiceExamples class:

static MetadataService.MetadataPort createService()
{
    MetadataService.MetadataPort service = new MetadataService.MetadataPort();
    service.SessionHeader = new MetadataService.SessionHeader_element();
    service.SessionHeader.sessionId = UserInfo.getSessionId();
    return service;
}
static List<MetadataService.SaveResult> createMetadata(MetadataService.Metadata input)
{
    return createService().createMetadata(new List<MetadataService.Metadata> { input });
}
static List<MetadataService.SaveResult> updateMetadata(MetadataService.Metadata input)
{
    return createService().updateMetadata(new List<MetadataService.Metadata> { input });
}
static List<MetadataService.DeleteResult> deleteMetadata(String type, String fullName)
{
    return createService().deleteMetadata(type, new List<String> { fullName });
}

NamedCredential

I tried to run a NamedCredential through these methods and was not able to get createMetadata or updateMetadata to work. The errors are included below. To my surprise, however, deleteMetadata runs successfully if the other methods are left out. I don't see any mention in the documentation of which operations are supported...

Script

MetadataService.NamedCredential credential = new MetadataService.NamedCredential();
credential.fullName = 'Demo_Credential';
credential.label = 'Demo Credential';
credential.endpoint = 'https://www.DEMO2.com';

system.debug(createMetadata(credential));
system.debug(updateMetadata(credential));
system.debug(deleteMetadata('NamedCredential', credential.fullName));

Error on createMetadata

Line: 11534, Column: 1
System.CalloutException: Web service callout failed: WebService returned a SOAP Fault: '' is not a valid value for the enum 'ExternalPrincipalType' faultcode=soapenv:Client faultactor=

Error on updateMetadata

Line: 11364, Column: 1
System.CalloutException: Web service callout failed: WebService returned a SOAP Fault: '' is not a valid value for the enum 'ExternalPrincipalType' faultcode=soapenv:Client faultactor=

ApexPage

Just to make sure my installation works correctly, I slightly tweaked some examples from the MetadataServiceExamples class. The createMetadata(), updateMetadata(), and deleteMetadata() calls each work fine for the ApexPage type.

Script

MetadataService.ApexPage apexPage = new MetadataService.ApexPage();
apexPage.apiVersion = 25;
apexPage.fullName = 'test';
apexPage.label = 'Test Page';
apexPage.content = EncodingUtil.base64Encode(Blob.valueOf('<apex:page/>'));

system.debug(createMetadata(apexPage));
system.debug(updateMetadata(apexPage));
system.debug(deleteMetadata('ApexPage', apexPage.fullName));

Abbreviated Logs

(SaveResult:[errors=null, fullName=test, success=true])
(SaveResult:[errors=null, fullName=test, success=true])
(DeleteResult:[errors=null, fullName=test, success=true])

6
  • 1
    On the docs developer.salesforce.com/docs/atlas.en-us.api_meta.meta/… there's a ExternalPrincipalType enum. Maybe you need to put a value while setting up the named credential? Commented Mar 22, 2017 at 17:52
  • You'll probably need a protocol as well Commented Mar 22, 2017 at 17:53
  • 1
    @FernandoGavinho Interesting, I searched for it in the documentation but didn't see it for some reason.
    – Adrian Larson
    Commented Mar 22, 2017 at 17:53
  • @FernandoGavinho Right on both counts. If you can whip up an answer that verifies as much I will accept it. Not sure if you have the package installed anywhere... If it's too much work I can also answer it myself.
    – Adrian Larson
    Commented Mar 22, 2017 at 18:05
  • Hi @AdrianLarson did you install whole mdapi wrapper package from financialforce or you extracted only some piece of code those were necessary ?
    – Vickal
    Commented Feb 6, 2021 at 7:53

2 Answers 2

10

You need to add two required "fields" to your request: principalType and protocol (you can see the entire list of fields here)

Script

MetadataService.NamedCredential credential = new MetadataService.NamedCredential();
credential.fullName = 'Demo_Credential';
credential.label = 'Demo Credential';
credential.endpoint = 'https://www.DEMO2.com';
credential.principalType = 'NamedUser';
credential.protocol = 'NoAuthentication';

system.debug(createMetadata(credential));
system.debug(updateMetadata(credential));

Abbreviated logs

(SaveResult:[errors=null, fullName=Demo_Credential, success=true)
(SaveResult:[errors=null, fullName=Demo_Credential, success=true)

2
3

On v59.0, Salesforce has added some nice methods to work with Named Credentials / External Credentials without the need of installing apex-mdapi.

You can find some usage examples here, and the documentation of the Apex class here.

The caveat is that you can create both Named and External credentials, but only update External credentials.

You must log in to answer this question.

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