-
Notifications
You must be signed in to change notification settings - Fork 455
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add create named credential example (#494)
* Add create named credential example * Run prettier * Document makeCalloutWithNamedCredential method * Add tests * Suppress / fix PMD warnings * Skipping Permission Set setup when running tests * Increase API version * Add code review suggestions * Move mock to correct folder * Fix example * sample data setup fixed on CI jobs
- Loading branch information
Showing
12 changed files
with
472 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
force-app/main/default/classes/Integration Recipes/NamedCredentialRecipes.cls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/** | ||
* @description Demonstrates how to manage named credentials from Apex | ||
* @group Integration Recipes | ||
*/ | ||
public with sharing class NamedCredentialRecipes { | ||
public static final String NAMED_CREDENTIAL_MASTER_LABEL = 'GoogleBooksAPI (created with Apex)'; | ||
public static final String NAMED_CREDENTIAL_DEVELOPER_NAME = 'googleBooksAPIApex'; | ||
public static final ConnectApi.NamedCredentialType NAMED_CREDENTIAL_TYPE = ConnectApi.NamedCredentialType.SecuredEndpoint; | ||
public static final String NAMED_CREDENTIAL_CALLOUT_URL = 'https://www.googleapis.com/books/v1'; | ||
public static final Boolean NAMED_CREDENTIAL_ALLOW_MERGE_FIELDS_IN_BODY = false; | ||
public static final Boolean NAMED_CREDENTIAL_ALLOW_MERGE_FIELDS_IN_HEADER = false; | ||
public static final Boolean NAMED_CREDENTIAL_GENERATE_AUTH_HEADER = true; | ||
public static final String EXTERNAL_CREDENTIAL_MASTER_LABEL = 'GoogleBooksAPI (created with Apex)'; | ||
public static final String EXTERNAL_CREDENTIAL_DEVELOPER_NAME = 'googleBooksAPIApexExternal'; | ||
public static final ConnectApi.CredentialAuthenticationProtocol EXTERNAL_CREDENTIAL_AUTHENTICATION_PROTOCOL = ConnectApi.CredentialAuthenticationProtocol.Custom; | ||
public static final String PRINCIPAL_NAME = 'Developer Access'; | ||
public static final ConnectApi.CredentialPrincipalType PRINCIPAL_TYPE = ConnectApi.CredentialPrincipalType.NamedPrincipal; | ||
public static final Integer PRINCIPAL_SEQUENCE_NUMBER = 1; | ||
|
||
/** | ||
* @description Demonstrates how create a named credential from Apex. | ||
* @param connectApiWrapper instance of ConnectApiWrapper, created to allow mocking | ||
* @param permissionSetName name of the permission set that will have access to the external credential | ||
* @return ConnectApi.NamedCredential The created named credential | ||
* @example | ||
* System.debug(NamedCredentialRecipes.createNamedCredential(new ConnectApiWrapper(), 'Apex_Recipes')); | ||
* HttpResponse response = RestClient.makeApiCall( | ||
* NAMED_CREDENTIAL_DEVELOPER_NAME, | ||
* RestClient.HttpVerb.GET, | ||
* '/volumes?q=salesforce' | ||
* ); | ||
* System.debug(response.getBody()); | ||
**/ | ||
public static ConnectApi.NamedCredential createNamedCredential( | ||
ConnectApiWrapper connectApiWrapper, | ||
String permissionSetName | ||
) { | ||
// Create an external credential (you could use an existing one) | ||
ConnectApi.ExternalCredential externalCredential = NamedCredentialRecipes.createExternalCredential( | ||
connectApiWrapper, | ||
permissionSetName | ||
); | ||
|
||
// Create a list of external credential inputs and add the external credential name | ||
List<ConnectApi.ExternalCredentialInput> externalCredentials = new List<ConnectApi.ExternalCredentialInput>(); | ||
ConnectApi.ExternalCredentialInput externalCredentialInput = new ConnectApi.ExternalCredentialInput(); | ||
externalCredentialInput.developerName = externalCredential.DeveloperName; | ||
externalCredentials.add(externalCredentialInput); | ||
|
||
// Create a named credential input and setup the required fields | ||
ConnectApi.NamedCredentialInput namedCredentialInput = new ConnectApi.NamedCredentialInput(); | ||
namedCredentialInput.developerName = NAMED_CREDENTIAL_DEVELOPER_NAME; | ||
namedCredentialInput.masterLabel = NAMED_CREDENTIAL_MASTER_LABEL; | ||
namedCredentialInput.type = NAMED_CREDENTIAL_TYPE; | ||
namedCredentialInput.calloutUrl = NAMED_CREDENTIAL_CALLOUT_URL; | ||
namedCredentialInput.externalCredentials = externalCredentials; | ||
|
||
// Configure the named credential callout options | ||
ConnectApi.NamedCredentialCalloutOptionsInput calloutOptions = new ConnectApi.NamedCredentialCalloutOptionsInput(); | ||
calloutOptions.allowMergeFieldsInBody = NAMED_CREDENTIAL_ALLOW_MERGE_FIELDS_IN_BODY; | ||
calloutOptions.allowMergeFieldsInHeader = NAMED_CREDENTIAL_ALLOW_MERGE_FIELDS_IN_HEADER; | ||
calloutOptions.generateAuthorizationHeader = NAMED_CREDENTIAL_GENERATE_AUTH_HEADER; | ||
namedCredentialInput.calloutOptions = calloutOptions; | ||
|
||
// Create the named credential! | ||
return connectApiWrapper.createNamedCredential(namedCredentialInput); | ||
} | ||
|
||
/** | ||
* @description This example shows how to create an external credential in Apex. | ||
* An external credential contains the authentication and authorization information for the callout, | ||
* and needs to be linked to a named credential in order to be used. | ||
* @param connectApiWrapper instance of ConnectApiWrapper, created to allow mocking | ||
* @param permissionSetName name of the permission set that will have access to the external credential | ||
* @return ConnectApi.ExternalCredential The created external credential | ||
* @example | ||
* System.debug(NamedCredentialRecipes.createExternalCredential(new ConnectApiWrapper(), 'Apex_Recipes')); | ||
**/ | ||
private static ConnectApi.ExternalCredential createExternalCredential( | ||
ConnectApiWrapper connectApiWrapper, | ||
String permissionSetName | ||
) { | ||
ConnectApi.ExternalCredentialInput externalCredentialInput = new ConnectApi.ExternalCredentialInput(); | ||
externalCredentialInput.developerName = EXTERNAL_CREDENTIAL_DEVELOPER_NAME; | ||
externalCredentialInput.masterLabel = EXTERNAL_CREDENTIAL_MASTER_LABEL; | ||
externalCredentialInput.authenticationProtocol = EXTERNAL_CREDENTIAL_AUTHENTICATION_PROTOCOL; | ||
|
||
// Populate principals to connect the external credential to permissions | ||
ConnectApi.ExternalCredentialPrincipalInput principalInput = new ConnectApi.ExternalCredentialPrincipalInput(); | ||
principalInput.principalName = PRINCIPAL_NAME; | ||
principalInput.principalType = PRINCIPAL_TYPE; | ||
principalInput.sequenceNumber = PRINCIPAL_SEQUENCE_NUMBER; | ||
|
||
externalCredentialInput.principals = new List<ConnectApi.ExternalCredentialPrincipalInput>{ | ||
principalInput | ||
}; | ||
|
||
// Create external credential | ||
ConnectApi.ExternalCredential externalCredential = connectApiWrapper.createExternalCredential( | ||
externalCredentialInput | ||
); | ||
|
||
if (!Test.isRunningTest()) { | ||
// Tests should skip giving permission set access, as principal doesn't really exist | ||
// Reload principal to get its id | ||
List<ConnectApi.ExternalCredentialPrincipal> principals = connectApiWrapper.getExternalCredential( | ||
EXTERNAL_CREDENTIAL_DEVELOPER_NAME | ||
) | ||
.principals; | ||
|
||
PermissionSet permissionSet = [ | ||
SELECT Id | ||
FROM PermissionSet | ||
WHERE Name = :permissionSetName | ||
WITH USER_MODE | ||
LIMIT 1 | ||
]; | ||
|
||
if (permissionSet != null) { | ||
// Give access to named principal on permission set | ||
insert as user new SetupEntityAccess( | ||
ParentId = permissionSet.Id, | ||
SetupEntityId = principals[0].Id | ||
); | ||
} | ||
} | ||
|
||
return externalCredential; | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
force-app/main/default/classes/Integration Recipes/NamedCredentialRecipes.cls-meta.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata"> | ||
<apiVersion>59.0</apiVersion> | ||
<status>Active</status> | ||
</ApexClass> |
32 changes: 32 additions & 0 deletions
32
force-app/main/default/classes/Shared Code/ConnectApiWrapper.cls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/** | ||
* @description Most Connect in Apex methods require access to real organization data, | ||
* and fail unless used in test methods marked @IsTest(SeeAllData=true). | ||
* An alternative to that, is mocking the calls to the ConnectAPI class. | ||
* This class can be used to inject the ConnectAPI dependency, | ||
* allowing its methods to be mocked in test classes. | ||
* @group Shared Code | ||
* @see NamedCredentialRecipesTest | ||
*/ | ||
public with sharing class ConnectApiWrapper { | ||
public ConnectApi.ExternalCredential createExternalCredential( | ||
ConnectApi.ExternalCredentialInput externalCredentialInput | ||
) { | ||
return ConnectApi.NamedCredentials.createExternalCredential( | ||
externalCredentialInput | ||
); | ||
} | ||
|
||
public ConnectApi.NamedCredential createNamedCredential( | ||
ConnectApi.NAmedCredentialInput namedCredentialInput | ||
) { | ||
return ConnectApi.NamedCredentials.createNamedCredential( | ||
namedCredentialInput | ||
); | ||
} | ||
|
||
public ConnectApi.ExternalCredential getExternalCredential( | ||
String developerName | ||
) { | ||
return ConnectApi.NamedCredentials.getExternalCredential(developerName); | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
force-app/main/default/classes/Shared Code/ConnectApiWrapper.cls-meta.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata"> | ||
<apiVersion>59.0</apiVersion> | ||
<status>Active</status> | ||
</ApexClass> |
19 changes: 19 additions & 0 deletions
19
force-app/main/default/staticresources/documentation/ConnectApiWrapper.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# ConnectApiWrapper | ||
|
||
Most Connect in Apex methods require access to real organization data, | ||
and fail unless used in test methods marked | ||
|
||
|
||
**IsTest** (SeeAllData=true). An alternative to that, is mocking the calls to the ConnectAPI class. This class can be used to inject the ConnectAPI dependency, allowing its methods to be mocked in test classes. | ||
|
||
|
||
**Group** Shared Code | ||
|
||
|
||
**See** [NamedCredentialRecipesTest](NamedCredentialRecipesTest) | ||
|
||
## Methods | ||
### `public ConnectApi createExternalCredential(ConnectApi externalCredentialInput)` | ||
### `public ConnectApi createNamedCredential(ConnectApi namedCredentialInput)` | ||
### `public ConnectApi getExternalCredential(String developerName)` | ||
--- |
103 changes: 103 additions & 0 deletions
103
force-app/main/default/staticresources/documentation/NamedCredentialRecipes.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# NamedCredentialRecipes | ||
|
||
Demonstrates how to manage named credentials from Apex | ||
|
||
|
||
**Group** Integration Recipes | ||
|
||
## Fields | ||
|
||
### `public EXTERNAL_CREDENTIAL_AUTHENTICATION_PROTOCOL` → `ConnectApi` | ||
|
||
|
||
### `public EXTERNAL_CREDENTIAL_DEVELOPER_NAME` → `String` | ||
|
||
|
||
### `public EXTERNAL_CREDENTIAL_MASTER_LABEL` → `String` | ||
|
||
|
||
### `public NAMED_CREDENTIAL_ALLOW_MERGE_FIELDS_IN_BODY` → `Boolean` | ||
|
||
|
||
### `public NAMED_CREDENTIAL_ALLOW_MERGE_FIELDS_IN_HEADER` → `Boolean` | ||
|
||
|
||
### `public NAMED_CREDENTIAL_CALLOUT_URL` → `String` | ||
|
||
|
||
### `public NAMED_CREDENTIAL_DEVELOPER_NAME` → `String` | ||
|
||
|
||
### `public NAMED_CREDENTIAL_GENERATE_AUTH_HEADER` → `Boolean` | ||
|
||
|
||
### `public NAMED_CREDENTIAL_MASTER_LABEL` → `String` | ||
|
||
|
||
### `public NAMED_CREDENTIAL_TYPE` → `ConnectApi` | ||
|
||
|
||
### `public PRINCIPAL_NAME` → `String` | ||
|
||
|
||
### `public PRINCIPAL_SEQUENCE_NUMBER` → `Integer` | ||
|
||
|
||
### `public PRINCIPAL_TYPE` → `ConnectApi` | ||
|
||
|
||
--- | ||
## Methods | ||
### `public static ConnectApi createNamedCredential(ConnectApiWrapper connectApiWrapper, String permissionSetName)` | ||
|
||
Demonstrates how create a named credential from Apex. | ||
|
||
#### Parameters | ||
|
||
|Param|Description| | ||
|---|---| | ||
|`connectApiWrapper`|instance of ConnectApiWrapper, created to allow mocking| | ||
|`permissionSetName`|name of the permission set that will have access to the external credential| | ||
|
||
#### Returns | ||
|
||
|Type|Description| | ||
|---|---| | ||
|`ConnectApi`|ConnectApi.NamedCredential The created named credential| | ||
|
||
#### Example | ||
```apex | ||
System.debug(NamedCredentialRecipes.createNamedCredential(new ConnectApiWrapper(), 'Apex_Recipes')); | ||
HttpResponse response = RestClient.makeApiCall( | ||
NAMED_CREDENTIAL_DEVELOPER_NAME, | ||
RestClient.HttpVerb.GET, | ||
'/volumes?q=salesforce' | ||
); | ||
System.debug(response.getBody()); | ||
``` | ||
|
||
|
||
### `private static ConnectApi createExternalCredential(ConnectApiWrapper connectApiWrapper, String permissionSetName)` | ||
|
||
This example shows how to create an external credential in Apex. An external credential contains the authentication and authorization information for the callout, and needs to be linked to a named credential in order to be used. | ||
|
||
#### Parameters | ||
|
||
|Param|Description| | ||
|---|---| | ||
|`connectApiWrapper`|instance of ConnectApiWrapper, created to allow mocking| | ||
|`permissionSetName`|name of the permission set that will have access to the external credential| | ||
|
||
#### Returns | ||
|
||
|Type|Description| | ||
|---|---| | ||
|`ConnectApi`|ConnectApi.ExternalCredential The created external credential| | ||
|
||
#### Example | ||
```apex | ||
System.debug(NamedCredentialRecipes.createExternalCredential(new ConnectApiWrapper(), 'Apex_Recipes')); | ||
``` | ||
|
||
|
||
--- |
Oops, something went wrong.