Question
Is it possible to create or update a
NamedCredential
from withinApex
?Investigation
I looked into available options, and it seems the
SOAP API
only supports thedescribeSObjects()
,query()
, andretrieve()
operations. TheTooling API
doesn’t seem to support the object at all. But theMetadata API
does!Let’s play around with some scripts in
Execute Anonymous
and see what we can do with theApex 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 getcreateMetadata
orupdateMetadata
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. ThecreateMetadata()
,updateMetadata()
, anddeleteMetadata()
calls each work fine for theApexPage
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])
Answer
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)
Attribution
Source : Link , Question Author : Adrian Larson , Answer Author : Fernando Gavinho