NTO Sample App Part 2: Using Platform Events to Integrate Salesforce and Node.js

Platform Events (new in Summer ’17) provide a powerful publish/subscribe infrastructure that facilitates the integration between Salesforce and other applications. In this blog post, I demonstrate how to use platform events to integrate a Salesforce app with a Node.js app running on Heroku.

In my previous post, I shared a sample retail application called Northern Trail Outfitters (NTO). The application allows NTO to manage their relationship with retailers. For example, NTO reps can create “merchandise mixes” for their large retailers. A merchandise mix is a collection of products a retailer carries for a season.

In this post, we examine how the NTO retail app (built on force.com) integrates with their manufacturing app (built on Node.js). Here are the simple integration requirements:

  • When a user changes the status of a merchandise mix to “Submitted to Manufacturing” in the retail app, the manufacturing app needs to be notified.
  • When a user approves a merchandise mix in the manufacturing app, the retail app needs to be notified so it can change the mix status to “Approved by Manufacturing”.

Watch the video to see the integration in action:

Architecture

Integration without Platform Events

Without platform events, you typically implement this kind of integration with API calls between apps. For example:

  • The retail app (force.com) would call a REST service in the manufacturing app (Node.js) to let it know a new merchandise mix has been submitted.
  • The manufacturing app (Node.js) app would call a REST service in the retail app (force.com) to let it know the merchandise mix has been approved. Alternatively, the manufacturing app could also use the Salesforce REST API to directly change the status of a merchandise mix in Salesforce.

The downside of this approach is that it tightly couples the two applications:

  • The retail app has to know about the manufacturing app and the services it exposes.
  • The manufacturing app has to know about the retail app and the services it exposes, or the structure of its data model.

If you change a REST service endpoint in one app, you’ll have to change code in the app that calls it. It gets worse when the integration involves more than two systems. Imagine for example that when a merchandise mix is approved in the manufacturing app, you have to do the following:

  1. Call a service in the retail app to change the merchandise mix status to “Approved by Manufacturing”
  2. Call a service in a Marketing Automation App like Pardot to send a confirmation email to the retailer
  3. Call a service in another app to do something else

These service calls can be orchestrated in different ways, but in general this API-based approach leads to tightly coupled apps, and harder to maintain integrations.

Integration with Platform Events

Platform events allow you to communicate between applications while keeping them entirely decoupled. For example, in the NTO scenario, the platform events-based integration works as follows:

  • When a mix is submitted to manufacturing, the retail app publishes a Mix_Submitted__e platform event. The manufacturing app subscribes to that event and any other interested (and authorized) app can subscribe to it as well.
  • When a mix is approved, the manufacturing app publishes a Mix_Approved__e platform event. The retail app subscribes to that event and any other interested (and authorized) app can subscribe to it as well.

The retail app isn’t even aware of the existence of the manufacturing app, and the manufacturing app doesn’t know about the retail app either. Using the platform events approach, it doesn’t matter how many apps you need to integrate. You can add applications to the integration without having to change code in other apps. This generally leads to more versatile and easier to maintain integrations.

Code Highlights

Publishing a Platform Event in Salesforce

A platform event looks like a custom object with a few differences:

  • The suffix is __e instead of __c
  • Only a subset of data types are available
  • Platform events are not persisted
  • Platform events are put on an event bus and apps can “listen to them” (subscribe to them)

Publishing a platform event is very similar to creating a custom object. You can do it in Apex like this:

Mix_Submitted__e event = new Mix_Submitted__e();
event.Mix_Id__c = mix.Id;
event.Mix_Name__c = mix.Name;
EventBus.publish(event);

You can also do it entirely declaratively using a Create Record action in Process Builder. For example, in the NTO application, the Mix Status Change process creates a Mix_Submitted__e event when the status of a merchandise mix is changed to “Submitted to Manufacturing”.

Subscribing to Platform Events in a third-party app

Third-party apps subscribe to platform events using CometD. CometD libraries and toolkits are available for different platforms including Java and JavaScript. The manufacturing app is a Node.js app running on Heroku. It uses the Faye Node.js module to subscribe to CometD events (Mix_Submitted__e and Mix_Unsubmitted__e). Using Faye, the code to subscribe to a platform event in Node.js looks like this:

var client = new faye.Client(org.oauth.instance_url + '/cometd/40.0/');
client.setHeader('Authorization', 'OAuth ' + org.oauth.access_token);
client.subscribe('/event/Mix_Submitted__e', function(message) {
    console.log('Got Mix_Submitted__e');
});

Publishing a Platform Event in a third-party app

When a merchandise mix is approved, the manufacturing app publishes a Mix_Approved__e platform event to notify interested parties. You publish a platform event the same way you create a custom object. In a third-party application, this means you call the Salesforce REST API create record endpoint, or the facility provided by your Salesforce REST API toolkit to create a custom object. The manufacturing app uses the nforce library. The code to publish the Mix_Approved__e platform event in Node.js looks like this:

let event = nforce.createSObject('Mix_Approved__e');
event.set('Mix_Id__c', mixId);
event.set('Confirmation_Number__c', confirmationNumber);
org.insert({sobject: event}, err => {
    if (err) {
        console.error(err);
    } else {
        console.log("Mix_Approved__e published");
    }
});

Subscribing to Platform Events in Apex

The retail app “listens” to the Mix_Approved__e event so it knows when a merchandise mix has been approved and can change its status accordingly. To subscribe to a platform event in Apex, you create an “after insert” trigger for the event type. The code to subscribe to the Mix_Approved__e platform event in Apex looks like this:

trigger onMixApproved on Mix_Approved__e (after insert) {

    List mixes = new List();

    for (Mix_Approved__e event : Trigger.New) {
        Merchandising_Mix__c mix = new Merchandising_Mix__c();
        mix.Id = event.Mix_Id__c;
        mix.Status__c = 'Approved by Manufacturing';
        mix.Confirmation_Number__c = event.Confirmation_Number__c;
        mixes.add(mix);
    }

    update mixes;

}

Subscribing to a Platform Event in a Lightning Component

Lightning Components can also subscribe to platform events to update the UI in real time when events are fired. For example, if you are looking at a merchandise mix record page, it may be important to see that the mix has been approved in real time rather than having to constantly refresh the page or implement a polling mechanism. To subscribe to a Platform Event in a Lightning Component, you use the JavaScript CometD library. The code looks like this:

cometd.subscribe('/event/' + eventName, $A.getCallback(
    function(message) {
        console.log(message);
    }
));

Installation Instructions

  1. Install the NTO Retail app. Follow the instructions at the bottom of the NTO blog post. If you had already installed the application, make sure you pull the latest changes and push them to your scratch org:
    $ git pull origin master
    $ sfdx force:source:push
  2. Create a connected app as follows:
    • Connected App Name: NTO Manufacturing (or any name you want)
    • API Name: NTO_Manufacturing
    • Contact Email: enter your email address
    • Enabled OAuth Settings: Checked
    • Callback URL: http://localhost:3000/oauth/_callback
    • Selected OAuth Scopes: Full Access (full)
    • Click Save
  3. Write down the Consumer Key and the Consumer Secret of your connected app
  4. Create a password for the default user
    $ sfdx force:user:password:generate
  5. Install the NTO Manufacturing app on Heroku. Follow the instructions in the Northern Trail Manufacturing app repository.

Summary

Platform Events facilitate integration between applications by allowing them to communicate while keeping them entirely decoupled. This blog post demonstrates to use platform events to integrate a Salesforce app with a Node.js app running on Heroku. Try it out today. And because both the retail app (with Salesforce DX) and the manufacturing app are under version control in Github, it’s easier than ever to contribute to the project and submit pull requests!

Resources

Leave your comments...

NTO Sample App Part 2: Using Platform Events to Integrate Salesforce and Node.js