trailhead

Learning Objectives

After completing this unit, you'll be able to:

  • Understand how to use Apex callouts and workflow with Heroku.
  • Understand the use cases for Apex callouts and workflow.

Callouts to Heroku Apps

Sometimes events on Salesforce need to be handled by an external system due to the scale or type of process being executed. For instance, a user in Salesforce uploads an image that needs to be resized for future use. Heroku can receive an event from Salesforce and perform some process in response. Optionally, the output of the process could be stored back in Salesforce using the REST APIs or Heroku Connect.

Diagram showing a box with Salesforce and a Data Event that is triggered or sent from an outbound message. An arrow comes from the box and points to another box that contains all the apps that Heroku hosts

There are two primary methods to call a Heroku app based on an event in Salesforce: workflow outbound messages or Apex HTTP callouts. A workflow outbound message declaratively makes a SOAP call. An Apex HTTP callout programmatically makes a REST call to a Heroku app. Either way, the Heroku app receives a request with the event details payload and then performs the action.

To learn more about Workflow in general, check out the Automating Time-based Actions with Workflow Trailhead Unit.

Callouts with Workflow

With workflow, you declaratively define a rule and a callout to an external system. The rule can be connected to any Salesforce object, like Contact or Account, and be triggered based on these record events:

  • Created
  • Created, and every time it's edited
  • Created, and any time it's edited to subsequently meet criteria

Rules must have criteria that filter the events. If you don't want to do any filtering, you can add a criteria that is always true. Here is an example rule:

Screenshot of the Configure Workflow Rule dialog showing that the rule name should be New Contact

To call a Heroku app when the rule executes, add an outbound message to the list of immediate workflow actions and specify a Heroku app endpoint as the endpoint URL, like:

Screenshot of the Configure OUtbound Messaging dialog, showing the message named New Contact to Heroku

If you select Send Session ID, the Heroku app can use that token to make REST API calls on the user’s behalf. If you don't send the session ID. there's no way to check that the request was valid or protect against malicious calls to your Heroku app’s API endpoint.

On the Heroku side, you can implement the event handler with any open-source web or REST technology. But because the message is in SOAP format, you need to be able to parse the XML. For instance, with JavaScript, Node.js, Express, and the express-xml-bodyparser library, here is an endpoint that handles an outbound message and parses the SOAP message.

app.post("/new_contact", function(req, res) { var notification = req.body["soapenv:envelope"]["soapenv:body"][0]["notifications"][0]; var sessionId = notification["sessionid"][0]; var data = {}; if (notification["notification"] !== undefined) { var sobject = notification["notification"][0]["sobject"][0]; Object.keys(sobject).forEach(function(key) { if (key.indexOf("sf:") == 0) { var newKey = key.substr(3); data[newKey] = sobject[key][0]; } }); // do something #awesome with the data and sessionId } res.status(201).end(); }); 

In this example, each time a contact is created, the Heroku app receives the contact details and can do whatever it needs to with the data.

Callouts with Apex Triggers

You can define Apex triggers on Salesforce objects to handle any of these events:

  • insert
  • update
  • delete
  • merge
  • upsert
  • undelete

The trigger can use an Apex callout to make a REST JSON call to an endpoint on a Heroku app. For instance, here is an Apex trigger that calls a Heroku app:

trigger NewContactWebhookTrigger on Contact (after insert) { String url = 'https://foo.herokuapp.com/new_contact'; String content = Webhook.jsonContent(Trigger.new, Trigger.old); Webhook.callout(url, content); } 

The referenced Webhook Apex class is:

public class Webhook { public static String jsonContent(List<Object> triggerNew, List<Object> triggerOld) { String newObjects = '[]'; if (triggerNew != null) { newObjects = JSON.serialize(triggerNew); } String oldObjects = '[]'; if (triggerOld != null) { oldObjects = JSON.serialize(triggerOld); } String userId = JSON.serialize(UserInfo.getUserId()); String content = '{"new": ' + newObjects + ', "old": ' + oldObjects + ', "userId": ' + userId + '}'; return content; } @future(callout=true) public static void callout(String url, String content) { Http h = new Http(); HttpRequest req = new HttpRequest(); req.setEndpoint(url); req.setMethod('POST'); req.setHeader('Content-Type', 'application/json'); req.setBody(content); h.send(req); } } 

The jsonContent method takes the trigger data and serializes it into JSON. The callout method makes the HTTP post to Heroku with the JSON payload.

As with outbound messages, you can build the Heroku app with any open-source web or REST technology. With JavaScript, Node.js, and Express, the endpoint could be defined as:

app.post("/new_contact", function(req, res) { // do something with req.body res.status(201).end(); }); 

In the request handler, the req.body is the deserialized JSON data sent from the Apex trigger.

With Apex triggers, you can use some form of pre-shared key to authenticate requests, avoiding the potential for malicious requests. You can also have the payload include a session ID to let the Heroku app make REST API requests back to Salesforce to fetch or update data.

Resources

Time Estimate
Topics
retargeting