Week of 3/8/21

Week of 3/8/21

This week, I started studying for my Integration Architect exam, which would be my 7th SFDC certification as of 3/15/21. One of the major topics of the exam is use cases for External Objects, an integration feature that makes data from sources outside of Salesforce available in your Salesforce org as an object. This means you can query data from an external system as easily as any other object* in your org.

My goal was to integrate a service that I already use extensively. Alongside my usual work at Salesforce with my usual tools such as Visual Studio Code and Postman, my most used program would be the time tracking browser extension Toggl, which I use to classify work hours. Getting time tracking data in Salesforce could be especially useful for reports and dashboards, so this sounds like it could be useful to any Salesforce user who uses Toggl for time tracking purposes.

External Objects: Custom Apex Adapters

After reviewing the Toggl API, it looks like this one will need a custom Apex adapter for an external object configuration. External objects require a Salesforce Connect Adapter, which just defines how to translate the data into a Salesforce object. There are a few supported types out of the box:

  • Cross-org (Salesforce-to-Salesforce)
  • OData 2.0 & OData 4.0

So if your endpoint supports OData, you just plug in the URL and you're good to go. However, some APIs (like the Toggl Track API) only support REST queries. So in order to create an External Object for this resource, we'll need to implement a custom Apex connector. Salesforce provides the DataSource.Connection class to implement these connectors. Since we're just interested in reading data from Toggl to see time tracking data in our Salesforce org, we'll just implement the sync and query methods.

For sync, we need to define our external data structure. We'll be querying against the Toggl time entries API. There are a lot of fields in a Toggl Track API request, and we'll make use of as many as we can

// internal external ID field (required)
columns.add(DataSource.Column.text('ExternalId', 255));
// display URL defined as https://track.toggl.com/ (required)
columns.add(DataSource.Column.url('DisplayUrl'));
// label of the timetracking session
columns.add(DataSource.Column.text('description'));
// unique ID (used as the External ID)
columns.add(DataSource.Column.text('guid'));
// Toggl user ID
columns.add(DataSource.Column.text('uid'));
// Start time
columns.add(DataSource.Column.text('start'));
// End time
columns.add(DataSource.Column.text('stop'));
// Is billiable time (boolean)?
columns.add(DataSource.Column.boolean('billable'));
// Duration in seconds
columns.add(DataSource.Column.integer('duration',18));

For the sync method, we'll need to define how to connect to the API. Toggl requies authorization in the form of a basic authorization header:

{api_key}:api_token

We can create this with a named principal in setup:

No alt text provided for this image
  • Yes, the username is the actual API key and the password is "api_token" and I don't know why that is  ¯\_(ツ)_/¯

Now, in our query method, we can initiate the API connection to Toggl:

Http httpProtocol = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('callout:Toggl/api/v8/time_entries');
request.setMethod('GET');
HttpResponse response = httpProtocol.send(request);
     

When we get the response, we need to define our initial properties:

List<Map<String, Object>> properties = new List<Map<String, Object>>();
for (Object item : (List<Object>)JSON.deserializeUntyped(response.getBody())) {
  Map<String, Object> property = (Map<String, Object>)item;
   property.put('ExternalId', property.get('guid'));
   property.put('DisplayUrl', 'https://track.toggl.com/')
   properties.add(property);
}

Once we've synced our object, we can add a custom object tab in setup, and then we can browse our time entires in Lightning Experience:

No alt text provided for this image

And just like that, we have our data available in Salesforce! Full integration with Lightning in less than 70 total lines of code. Of course, there are additional considerations with this specific API:

  • With the default Toggl time entries endpoint, it only retrieves the last 9 days of results. We'd either want to create a batch class to sync the External Object data to permanent records in Salesforce or modify the query code to use a specified date range
  • Toggl supports complex project and group hierarchy, so we could consider incorporating those fields into some processes in Apex or Lightning Components so we could better organize time entries.

As always, the relevant code can be found on my Github page.

Thanks, and have fun!

* By default, external objects are read-only but can be written to using Database.insertAsync and some custom Apex.

To view or add a comment, sign in

More articles by Evan Steele

  • 2023 Project Spring 2 - Mobile (Flutter)

    The second project sprint lasted from 1/16 to 1/27 and focused on the multi-platform mobile framework Flutter. Looking…

  • 2023 Project Sprint 1 - Intro (Qwik)

    In 2021, I indexed each* week in my role at Salesforce with a summary of something I learned that week. This was a good…

    1 Comment
  • Wrapping up 2021

    I've decided to wrap-up my 2021 posting schedule with a reflection on how I've handled my post schedule & topic areas…

    2 Comments
  • Week of 9-6-21

    Why is the headline above the image now? Not sure. This week I spent some time going over some more configuration…

  • Week of 8-30-21

    A really quick thing regarding Messaging Session objects, but one that I find people stumbling over from time to time…

  • Week of 8-23-21

    Lightning Web Components & Embedded Service objects We have a well-documented process for passing values from a custom…

  • Week of 8-16-21

    With a recent release, Salesforce added a way to implement custom routing using Lightning Flows, with Omni-Channel…

  • Week of 8-2-21

    I've rarely gotten into reporting in Salesforce, as it's always been something that usually falls well outside my…

  • Week of 7-26-21

    In general, when using Omni-Channel routing, we want things to happen quickly with respect to getting the right work…

  • Week of 8-16-21

    Bots have a lot of click-n-drag functions that work well out of the box, with little room for unexpected errors or…

Others also viewed

Explore content categories