Development, Integration

[ART-014] Callout Framework Part 1


Callout means calling an external endpoint from Salesforce mostly through APEX when you have to integrate your org with any others systems. Basically, there is nothing very complex on implementing this, but what happens when you need to change something, when the external system resource is not ready or not yet developed, when you need to validate your feature without the availability of external resources and finally how can you test and track everything ? In this article, you will explore the new features of the framework helping you to achieve all of these.


Prerequisites

Before starting, I will recommend you to read my previous article because I will reuse some components that you will need to put in place :

https://ssdevl.com/2021/03/03/art-013-node-js-oauth2-on-heroku-with-salesforce/

Step 1

Now it’s time to open your Salesforce Developer Edition instance and create a new Connected App.

SettingValue
Connected App NameMy Auth
API NameMyAuth
Contact Emailintegration@yourmail.com
Enable OAuth SettingsChecked
Use digital signaturesNot Checked
Callback URLEnter some fake url for now, we will replace it later
scopeAccess and manage your data (api), Access your basic information (id, profile, email, address, phone) , Perform requests on your behalf at any time (refresh_token,offline_access), Provide access to your data via the Web (web)
run asLeave it blank
Introspect All TokensChecked

There are some important points here around the scope used. In the following example, I will need to access Salesforce Data, I will need to give access to my profile information, I will need to get a new access token through refresh token every time my session is expired and I will need to give access through the web in order to use the OAUTH Flow.

Save the new Connected App and wait a few minutes (2-10mn really it won’t work otherwise), and then copy the generated consumer key and consumer secret that will be used in next steps.

Step 2

Click on Manage and then edit policies and make sure you have the following options :

  • All users may self-authorize
  • Enforce IP restrictions
  • Refresh token is valid until revoked (Important to get new access token after session expiration)
  • Session Policies – Timeout values : 15 minutes (so we can test the refresh token behavior)

Well, you may ask me why we are creating a Connected App for making callout ? Yes, you don’t have to but you will see the benefit of it later on 😉

Step 3

Now, let’s create an Auth. Provider:

Then fill in the following values:

SettingValue
Provider TypeSalesforce
NameMySalesforceIDP
URL SuffixMySalesforceIDP
Consumer KeyLeave it blank for now
Consumer SecretLeave it blank for now
Authorization Endpoint URLLeave it blank for now
Token Endpoint URLLeave it blank for now
Default Scopesrefresh_token offline_access api id profile email address phone web
Include Consumer Secret In API ResponsesChecked

After saving your Auth. provider, you will get the generated callback URL, copy it and paste it in the callback URL of your Connected App:

https:// [youdomain] /services/authcallback/MySalesforceIDP

Go back now to the Auth. Provider you have created previously and fill in the following values:

SettingValue
Provider TypeSalesforce
NameMySalesforceIDP
URL SuffixMySalesforceIDP
Consumer KeyCopied from Connected App
Consumer Secret Copied from Connected App
Authorization Endpoint URL[your domain]/services/oauth2/authorize
Token Endpoint URL [your domain]/services/oauth2/token
Default Scopesrefresh_token offline_access api id profile email address phone web
Include Consumer Secret In API ResponsesChecked

To resume, we have a Connected App configured to allow incoming calls to Salesforce using OAUTH2 and we have configured Salesforce as an Auth. Provider that will use the Connected App to authorize incoming calls. At this point, it can still be confusing for you why we have these 2 setup in place while we are talking about callout, keep in mind that we are preparing the playground 😉

Step 4

Now it’s time to create 2 Named Credentials which are metadata used to setup authorization per org. The first one will be used to authenticate against Salesforce itself and for this I will rely on the previously created Auth. Provider through OAUTH2 protocol.

Fill in the following information and save:

SettingValue
LabelMy Salesforce
NameMySalesforce
URL[your domain]
Identity TypeNamed Principal
Authentication ProtocolOAUTH2
Authentication providerMySalesforceIDP
Scoperefresh_token offline_access api id profile email address phone web
Start Authentication Flow on SaveChecked
Generate Authorization HeaderChecked
Allow Merge Fields in HTTP HeaderChecked
Allow Merge Fields in HTTP BodyChecked

While saving your configuration, you will be redirected to Salesforce Authentication page where you will have to provide username and password:

You will be then asked to authorize the access to the connected application:

You have now connected your user to the named credential MySalesforce that is connected to the Auth. Provider MySalesforceIDP which is also connected to the Connected App MyAuth.

Named Credentials are used by Callout to delegate the complexity and the administration of the endpoint settings, so by using this one you will be able to make callout from Apex to any services exposed by your Salesforce Org. Getting less confused now? 😉

Repeat the steps to create another named credential named MyHeroku which will be used this time to make callout to an external system:

Wondering why I’m setting up Salesforce as IDP here ? Well, if you have read my previous article, I was setting Salesforce as Authentication provider for my Heroku Application, so here by doing this, I’m able to send a bearer to Heroku that can be reused to callback Salesforce by Heroku. If you have another endpoint with its own authentication process you won’t need to do that.

Step 5

Now it’s time to configure the services that I will use for the example. The framework comes with a custommetadatatype named HttpServiceRequest__mdt which will be helpful to configure each resource to call.

Start by creating an entry for your Heroku Endpoint:

SettingValueDescription
LabelHeroku Service 01 To identify the service
Http request Service NameHEROKU_S01The name used in your APEX code
Service IdSID-0001Id used to identify resource in test context
Resource/securedThe resource path
Timeout120000Timeout to set in HttpRequest
Primary Named EndpointCALLOUT:MyHerokuCALLOUT: followed by the named credential
Secondary Named EndpointCALLOUT:MySalesforce/services/apexrestCALLOUT: followed by the named credential and path
Bypass Primary Endpoint PermissionLeave it blankName of the custom permission to use bypass feature
Force Secondary EndpointunCheckedSwitch to Secondary endpoint if checked
Custom Headers{“bearer”:”{!$Credential.OAuthToken}”, “instanceurl”:”[your domain]”}Special headers used in this callout in JSON

The setting is designed in the way that you are not relying on any platform dependent values, we will reference only the corresponding component holding those values. But for testing purpose you can replace named credentials with the full path.

Primary Named Endpoint will be the main path of your service but you can use a secondary path which can be used for backup, testing, mocking…

The activation of the secondary path can be global by checking the Force Secondary Endpoint so that this setting applies to all users, or it can be made per user by assigning a custom permission to your user, the name of this custom setting should be filled in the Bypass Primary Endpoint field to make the match.

The Custom Headers field will hold JSON formatted structure containing key/value pairs to be sent in the headers of the Http Request. In this example, my custom webservice on Heroku needs 2 values “bearer” and “instanceurl”, the “bearer” value will be resolved automatically through the named credential setting.

Let’s create now a second entry point for Standard Salesforce service:

SettingValueDescription
LabelSalesforce Service 01 To identify the service
Http request Service NameSFDCThe name used in your APEX code
Service IdSID-0002Id used to identify resource in test context
Resource/services/data/v50.0/sobjects/UserThe resource path
Timeout120000Timeout to set in HttpRequest
Primary Named EndpointCALLOUT:MySalesforceCALLOUT: followed by the named credential
Secondary Named EndpointblankCALLOUT: followed by the named credential
Bypass Primary Endpoint PermissionLeave it blankName of the custom permission to use bypass feature
Force Secondary EndpointunCheckedSwitch to Secondary endpoint if checked
Custom HeadersLeave it blankSpecial headers used in this callout in JSON

You can now use this setting to call the API from you APEX code.

Step 6

At this point, you have setup everything to play but you need something to trigger it.

Here’s a simple way to test our Salesforce service, copy/paste the code below in the developer console and run it:

ITF004_HttpRequestManager dm = new DM003_HttpRequestService('SFDC');
WRP003_HttpRequest inf = new WRP003_HttpRequest();
inf.requestType = 'GET';
inf.queryParameters = '/'+UserInfo.getUserId();
dm.sendRequest(inf);

system.debug('Callout results: ' +inf.httpResponse.getBody());

The output will be:

Callout results: {"attributes":{"type":"User","url":"/services/data/v50.0/sobjects/User/0051x0000062wVYAAY"},"Id":"0051x0000062wVYAAY","Username":"test-wurrhwlghspg@example.com","LastName":"User","FirstName":"User","Name":"User User","CompanyName":"SSDEVL","Division":null,"Department":null,"Title":nul (....)

The code will retrieve configuration using the name “SFDC”, add the Id of the connected user to the query and get information on user from an API call.

Step 7

The next example will be more sophisticated, I will need to expose a custom webservice in Salesforce that will mock an external webservice.

You can use the code below in your org to test the use case:

@RestResource(urlMapping='/secured/*')
global inherited sharing class RestUtil {
   
    @HttpGet
    global static void mockHeroku(){
        RestResponse res = RestContext.response;
        res.responseBody  = Blob.valueOf('Accessing Secured Resources (Mock)');
    }
}

Important things to retain here is that we have named the resource with the same name as the real resource on Heroku, only the endpoint will be switched automatically. I’m returning a custom message to simulate the webservice call.

You can then copy/paste the below code in your developer console to see the behavior:

ITF004_HttpRequestManager dm = new DM003_HttpRequestService('HEROKU_S01');
WRP003_HttpRequest inf = new WRP003_HttpRequest();
inf.requestType = 'GET';
dm.sendRequest(inf);

system.debug('Callout results: ' +inf.httpResponse.getBody());

The output will be:

Callout results: Accessing secured resource

The code will retrieve configuration using the name “HEROKU_S01” and make an API call to Heroku resource. The Heroku resource will authenticate back into Salesforce before providing access to the secured resource.

Now, go back to the Heroku Service configuration and check the field Force Secondary Endpoint and save:

Re execute the below code in your developer console:

ITF004_HttpRequestManager dm = new DM003_HttpRequestService('HEROKU_S01');
WRP003_HttpRequest inf = new WRP003_HttpRequest();
inf.requestType = 'GET';
dm.sendRequest(inf);

system.debug('Callout results: ' +inf.httpResponse.getBody());

The output will be:

Accessing Secured Resources (Mock)

The code will retrieve configuration using the name “HEROKU_S01” and make an API call to Salesforce resource. Hence, we see that we are able to route one service from one server to another server without changing any line of code. In this example, the switch was made globally for all users, but by declaring a custom permission, you will only need to assign this custom permission to route the user call without impacting others users.

Conclusion

In this article, we learn how to setup an OAUTH2 authentication using named credentials and Auth. provider. We also learn how to use the framework to manage properly callout resource setting and come up with a solution that enables the use of mock routing. In the next article, I will give you more insight on this framework and others capabilities.

Hope you enjoy reading this article, see you soon for the next one ...

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 )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.