A Simple Integration Approach for Simple Integration Needs

This is not a post about building enterprise-class integrations for Salesforce - built on a proven message-queuing infrastructure for resiliency and featuring extensive logging and management features. Potentially serving order fulfillment or some other critical business function.

This is about an arrow for your quiver when your client is looking for a simple integration to provide a productivity boost for users - the kind of scenario where the sky won’t fall if a hiccup occurs every now and again. This approach is so easy, that it may allow you to provide the productivity boosting power of integration in situations where more robust solutions are just not cost-effective.

The Scenario

My client in this scenario is a software company, where the sales and other customer-facing teams manage their work in Salesforce. The engineering team uses Atlassian Jira to manage the product development process.

The sales team had configured an object in Salesforce to mirror a user story in the product team’s Jira application. They wanted to have track feature requests and customer-impacting product bugs in Salesforce, linked to the related customers, and linked back to the related Jira story.

Great idea, with one obvious gotcha - how to keep the Salesforce “tracking object” up-to-date as the product team made updates to the related Jira story? It wouldn’t be practical or efficient to ask either sales or product to periodically log into the other team’s system and do some double data entry to keep everything in sync. Clearly, an integration was called for.

The Solution

Digging into the Atlassian documentation, Jira’s webhook solution seems like the basis for a solution. Jira can be configured to make a web call when issues are updated. You can even filter to have the call only made for certain Jira projects, and certain issue actions (e.g. like a status change).

So with an approach for “signaling” from Jira when an issue is updated in hand, all we need is an API to receive Jira’s web call and process it.

It turns out that AWS Lambda functions are well suited to this task - they are easy to set up, and easy to wire to an AWS API Gateway such that incoming web calls execute the Lambda function.

A short (27 lines of code!) Ruby function, using the httparty and restforce gems, takes the Jira issue id passed in from the web call from Jira, calls back into Jira to retrieve the issue details, and then uses the restforce gem to connect to the Salesforce REST API to query for the related Salesforce records and update them.

The solution ends up looking like this:

You may be wondering about the call back into Jira’s API to retrieve issue details - surely the Jira webhook can provide those details when it calls? It absolutely can… However, a critical limitation of Jira webhooks is that they don’t support authentication. So I am not trusting any information I get from the webhook, but going to the Jira API directly to get the issue details. I’ve also added a token to the webhook URL that I verify before doing anything as an added measure.

Summary

“Standing on the shoulders of giants” they say - in this case, on the shoulders of AWS and some slick ruby gems. They enable us to develop an easy integration that delivers value to users with a tiny investment in code.

I would be remiss in not ending this post where I began - please be smart about your integration approaches. This method is very easy, but not suitable for business-critical applications that must be resilient in the face of outages and disruptions, and must provide detailed logging and error handling.

UPDATE 01-02-2020

I kept working on this solution after posting this - and it turns out to be very easy to incorporate an AWS SQS message queue into the solution to provide some additional robustness and resilience. Your API Gateway, rather than calling a Lambda function, is configured to drop a message into the SQS queue in response to a call. Then your Lambda function is configured with SQS as the trigger, so that is polls the SQS queue periodically for messages, and processes any that it finds. You can configure the number of retries if a message fails to process, as well as the delay between tries. Lambda automatically deletes the SQS message after successfully processing it. Slick!