Catching Salesforce Outbound Messages with NodeJS

When building applications that are integrated with Salesforce, one of the choices you have to make is how you get data out of Salesforce and into your app. You can use one of the many ETL tools on the market, you can poll for changed records, use the Force.com Streaming API, use Apex HTTP Callouts from Salesforce or Outbound Messages.

I've covered most of these approaches in the past but have purposefully

overlooked Outbound Messages. Why? Because, in general, I hate working with XML. Perhaps it harkens back to my SAP days but every time I have to traverse an XML structure, I think a kitten dies somewhere.

However, with that said, Outbound Messages are quite magical. You hook them up as an action to your Workflow Rule, so that whenever a record is, for example, created or updated in some manner, the platform will fire off some record data to the endpoint specified in the Outbound Message. My only issue with them is that they only support XML and most web languages like Ruby, JavaScript, Go, etc. prefer JSON (and so do I). So here's a simple NodeJS app that will receive the XML from your Outbound Message and convert it into a JavaScript object that you can then use to do all sorts of awesome stuff!

You can find all of the code for this application at my github repo. What follows is the interesting part that catches the XML and parses it in routes/obm.js.

var express = require('express');  
var _ = require("lodash");  
var router = express.Router();

router.post('/', function(req, res) {  
  // get the obm as an object
  var message = unwrapMessage(req.body);
  if (!_.isEmpty(message)) {
    // some something #awesome with message
    console.log(message);
    // return a 'true' Ack to Salesforce
    res.send(
      '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:out="http://soap.sforce.com/2005/09/outbound"><soapenv:Header/><soapenv:Body><out:notificationsResponse><out:Ack>true</out:Ack></out:notificationsResponse></soapenv:Body></soapenv:Envelope>'
    );
  } else {
    // return a 'false' Ack to Salesforce
    res.send(
      '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:out="http://soap.sforce.com/2005/09/outbound"><soapenv:Header/><soapenv:Body><out:notificationsResponse><out:Ack>false</out:Ack></out:notificationsResponse></soapenv:Body></soapenv:Envelope>'
    );
  }

});

// unwrap the xml and return object
unwrapMessage = function(obj) {  
  try {

    var orgId = obj['soapenv:envelope']['soapenv:body'][0].notifications[0].organizationid[0];
    var contactId = obj['soapenv:envelope']['soapenv:body'][0].notifications[0].notification[0].sobject[0]['sf:id'][0];
    var mobilePhone = obj['soapenv:envelope']['soapenv:body'][0].notifications[0].notification[0].sobject[0]['sf:mobilephone'][0];

    return {
      orgId: orgId,
      contactId: contactId,
      mobilePhone: mobilePhone
    };

  } catch (e) {
    console.log('Could not parse OBM XML', e);
    return {};
  }
};

module.exports = router;  

Now we need to setup the Workflow and Outbound Message that will send the data to your NodeJS application. You'll want to change the Workflow to meet your criteria as this one fires every time a Contact record is created or updated and the mobile phone is not blank.

The actual Outbound Message below defines the endpoint (you'll notice I'm running it locally using ngrok), the fields from the record to include in the message (the record Id and MobilePhone) and finally "Send Session ID" is checked. You'll probably want to include the Session ID so that you can grab it from the message and use it to quickly make calls back into Salesforce using something like nforce.

If you want to test the application locally you can use something like ngrok to securely expose your local web server. Salesforce (thankfully) requires that all endpoints use HTTPS so ngrok comes in handy.

Now if you modify a Contact record in Salesforce, you should see the following in your terminal if everything is configured correctly:

There's also a mocha test you can run to ensure that the XML is being parsed correctly.

There you have it... a simple NodeJS app to get you started using Outbound Messages from Salesforce.

Cross-posted from the topcoder blog.