Introduction
One reason to create a custom connector for integrating Marketo with Salesforce is for connecting multiple SFDC orgs in order to segment the information sent to Marketo and sync only the desired records. This function is not currently supported by the Marketo Connector¹, and syncing records can take up to five minutes between each sync. If you need on demand or instant sync (at least from the SFDC side), you need a way to explicitly trigger the sync requests. Using Marketo's API and Apex you can build your own integration.
The Marketo API
The official Marketo’s documentation² is quite useful. It's well organized and provides examples, but for complex use cases and unexpected results, you'll need to research a bit to make it work³.
Accessing the resources requires authentication, which must be implemented. We will dive more deeply into this topic later on.
There are some best practices that need to be followed so as not to surpass the daily quota (number of API calls) or the rate limit (calls per second). This is important to keep in mind when designing your custom sync process, and is one of the reasons why the standard connector syncs every 5 minutes.
Implementation in Salesforce
The diagram below shows the big picture of the implementation using Apex classes. We won't delve into each element, but the main concepts seen here can be extrapolated to build any kind of integration.
IMarketoAPI (interface)
This interface will define all the possible interactions with the real API. One of the main benefits of creating an interface rather than just the concrete class is the ability to mock the responses within unit test classes. Most of the methods will return DTOs (Data Transfer Object) as a way of standardizing the results’ formats.
MarketoAPI
MarketoAPI can implement the interface and all its methods. Is in charge of making the Callouts to the Marketo endpoints and parsing the results. The URIs of the REST endpoints are declared as static variables, and are defined in the Named Credentials format:
Each of the actions that the Marketo API shows will be managed by a method. The methods (i.e getActivities) will use private general-purpose functions to send the HttpRequests and handle the HttpResponses.
When the access token expires, a specific status is returned by Marketo, and the send Request method will retry the connection. A failure request will need to be forced to allow the Named Credential to request a new access token.
MarketoAuthProvider
The authentication mechanism using Named Credentials requires the implementation of a custom OAuth-based authentication provider. Salesforce provides the Auth.AuthProviderPluginClass⁴ abstract class that needs to be extended, and the implemented class will be referenced in the Named Credentials settings from Setup. The Named Credentials feature will automatically refresh the access token when the invoked service returns a 401 status code⁵. The Marketo API is programmed to return a 601 status for invalid access tokens, which needs to be captured in the Apex class, and a failure needs to be forced. Fortunately, the Identity API (/identity/oauth/token) will return a 401 if the client id is invalid. Without this, the token request handshake must be implemented manually, with all the mplications of, for example, securely storing and caching those tokens.
PaginationTokenHandler
Marketo uses Paging Tokens⁶ to retrieve events that occur after a certain date. The endpoint to ask for a new token is implemented in the MarketoAPI class. Based on the Singleton pattern⁷, this class was built to support the change of the implementation class. As the following code snippet shows, the ternary operator⁸ was used to set a default implementation of the interface, but we still allow the use of a stub for the unit tests, which we will review later.
Unit testing
For testing the external call outs, a Mock created from the HttpCalloutMock must be used to simulate the responses. A similar pattern can be followed to isolate the state and behavior of the API from the business logic. The interface defined plays a key role here, as you'll be able to implement a deterministic class with results you expect to return. Using dependency injection, you can define the mocked API class with predefined results, and set it on the dependent service during the unit test execution.
Tools
Postman is a particularly useful app for dealing with APIs and provides many helpful features. If you are discovering Marketo or any other API that is well documented, but does not have built-in web application tools to test the request, you can try a trial and error approach. With Postman, you can automate the authentication, being able to ask for a JWT token before each request.
Conclusions
Breaking the dependency between the business logic and external service connection by using interfaces and mocks will allow the creation and distribution of a package (future work).
Having interfaces that can be reused throughout your classes is great, but exposing methods that could be called from Flows or even Process Builder is even greater.
Besides using interfaces for accessing Marketo, there are some common patterns that you can reuse to improve connection with other services. Security handling, unit testing, and reusability are some of the key considerations you should make when building enterprise solutions.
At Tero by Nearsure we always deliver top quality service. Our team is constantly researching best practices and top notch solutions to drive the most effective and scalable solutions.
References:
- Understanding the Salesforce Sync: Understanding theSalesforce Sync | Adobe Marketo
- https://developers.marketo.com/rest-api/
- Read This BeforeUsing Marketo’s Weird REST API: https://www.linkedin.com/pulse/read-before-using-marketos-weird-rest-api-jep-castelein
- https://developer.salesforce.com/docs/atlas.en-us.234.0.apexref.meta/apexref/apex_class_Auth_AuthProviderPluginClass.htm
- Paging Tokens: https://developers.marketo.com/rest-api/paging-tokens/
- Singleton Pattern: https://blog.cleancoder.com/uncle-bob/2015/07/01/TheLittleSingleton.html
- Ternary Operator: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_expressions_operators_understanding.htm
- https://help.salesforce.com/s/articleView?language=en_US&type=1&id=000313355