node-red-contrib-salesforce-connection-emitter 1.4.3

A set of Node Red commands that allows nodes to better connect to salesforce (using environment variables, connection pools and config nodes)

npm install node-red-contrib-salesforce-connection-emitter

Overview

A set of Node Red commands that allows nodes to better connect to salesforce (using environment variables, connection pools and config nodes).

Many of the connections we have seen for Salesforce rely on creating a configuration node to store the credentials. This is then used by the various other nodes to connect to salesforce - each with their own connection.

We would instead like to ensure the following:

  • Credentials are secured using best practices
    • While explicitly stating credentials to the config / resulting JSON is sill allowed, environment variables are now also supported. (Providing greater reusability, support for heroku and security)
  • Connections are established at the Connection Credential and emitted to those dependent.
    • Child nodes can get notified of the current connection, when it is disconnected or request it be reset through events.
  • Support for ES6 Classes and subclassing
    • By providing classes that can be extended, listening for the events can become quite simple.

Nodes


connection.SfConnectionEmitter

Configuration Node - used by most (if not all of the other Salesforce commands.

When other nodes specify their type as sf-connection-emitter, then a drop-down dialog allows them to choose which configuration to use.

Each configuration manages the connection to salesforce, and emits events to those listening when:

  • (newConnection) - a connection is established
  • (connectionLost) - the connection has been disconnected
  • (refresh) - the connection should be restarted (logout and re-established)
  • (logout) - request the connection be severed

For nodes that subclass the connection.SfConnectionReceiver - this is all handled for you... For more information, please see that class

Screenshot of ConnectionEmitter

Configuration

Name Type Description Example
Name String Label to show in Node Red Editor SF Connection
Host string Domain to login with
OR name of environment variable
https://test.salesforce.com
or test.salesforce.com
or login.salesforce.com
or SF_HOST
Password string Password for that user
OR name of environment variable
(note: token does not use environment variable, so include in password if using environment variable)
t0tallyVALID!
or t0talyVALID!0abcd
or SF_PASSWORD
Security Token string Security Token for user 0abcd

Events

The SfConnectionEmitter dispatches four types of events, automatically handled by the

Each configuration manages the connection to salesforce, and emits events to those listening when:

  • (newConnection) - a connection is established
  • (connectionLost) - the connection has been disconnected
  • (refresh) - the connection should be restarted (logout and re-established)
  • (logout) - request the connection be severed

For nodes that subclass the connection.SfConnectionReceiver - this is all handled for you... For more information, please see that class


platformEvents.SfPlatformEventSubscriber

Use this to listen to Salesforce Platform Events

More on Platform Events can also be found on Trailhead.Salesforce.com

Name Type Description Example
Name String Label to show in Node Red Editor PE Subscription
Connection connection.SfConnectionEmitter The connection emitter configuration to use sfconn
Event API Name string Platform Event Object API Name ltng_Hello__e
The Replay Id to start listening to messages from. (-1 to only listen to those moving forward). See here for more information

NOTE: the replay Id captured is preserved for you automatically. To force the replay Id, configure it with an exclaimation mark / bang at the end: For example: 12!

Screenshot of subscription

As mentioned above, the replay Id captured is preserved for you automatically.

Note that this is preserved to be only visible to that same node, as opposed to the flow or within the whole project. Please see Node Red's documentation on Node Context for more

While this is a decent stop-gap, future work will allow it to be stored to external services (such as a Redis store).

To force the replay Id, configure it with an exclaimation mark / bang at the end: For example: 12!


platformEvents.SfPlatformEventPublisher

Use this to publish Salesforce Platform Events

Simply apply the object you want to publish as the msg.payload and it will handle the rest.

More on Platform Events can also be found on Trailhead.Salesforce.com

Name Type Description Example
Name String Label to show in Node Red Editor PE Subscription
Connection connection.SfConnectionEmitter The connection emitter configuration to use sfconn
Event API Name string Platform Event Object API Name ltng_Hello__e

Screenshot of Publisher


query.SfUniversalQuery

Use this to do a SOQL or Tooling API query within Salesforce.

Supports selection of the API, queries that can be (environment variables, global settings, property within a message, etc) and you can specify where the results go.

Example Flow

[{"id":"d2048d63.a9936","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"802b9dc4.7cebc","type":"inject","z":"d2048d63.a9936","name":"","topic":"","payload":"{\"query\":\"select id from Apexclass\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":140,"wires":[["3251ec56.5aef64"]]},{"id":"3251ec56.5aef64","type":"sf-universal-query","z":"d2048d63.a9936","name":"","sfconn":"73000fb4.ffb8e","api":"soql","query":"payload.query","queryType":"msg","target":"payload.some.result.somewhere","limit":100,"x":360,"y":140,"wires":[["a7b76b3.b6f7c98"]]},{"id":"a7b76b3.b6f7c98","type":"debug","z":"d2048d63.a9936","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":590,"y":140,"wires":[]},{"id":"73000fb4.ffb8e","type":"sf-connection-emitter","z":"","host":"SF_HOST","hostType":"env","username":"SF_USERNAME","usernameType":"env","password":"SF_PASSWORD","passwordType":"env","token":"","tokenType":"env"}]

Screenshot of universal query

Properties

Name Type Description Example
Name String Label to show in Node Red Editor Universal Query
Connection connection.SfConnectionEmitter The connection emitter configuration to use sfconn
API (SOQL|Tooling) The API to run the query against SOQL
Query * The query to run SELECT Id from Accounts (soql)
-OR-
SELECT Id,Name from ApexClass (tooling)
Target String The path within the message to put the results payload.results

describe.SfUniversalDescribe

Use this node to describe all objects or just a particular object using the Metadata API, Tooling API or SOAP API.

The name of the object to describe can also be defined either as a message property, or as a literal string.

Please note there is a bug with Node Red where the sobject appears required when it is not. The sobject is only required when not performing a describe all

Example Flow

[{"id":"7061841b.7dc20c","type":"tab","label":"Describe","disabled":false,"info":""},{"id":"ba6d47c3.0396f8","type":"inject","z":"7061841b.7dc20c","name":"Start","topic":"","payload":"{}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":80,"wires":[["806d933.686d77"]]},{"id":"806d933.686d77","type":"sf-universal-describe","z":"7061841b.7dc20c","name":"","sfconn":"73000fb4.ffb8e","api":"soap","describeAll":true,"objectName":"","objectNameType":"msg","target":"payload.describe","x":380,"y":80,"wires":[["221f1521.c786aa"]]},{"id":"221f1521.c786aa","type":"debug","z":"7061841b.7dc20c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":600,"y":80,"wires":[]},{"id":"ea764edf.67e0c","type":"comment","z":"7061841b.7dc20c","name":"Describe Everything","info":"","x":170,"y":40,"wires":[]},{"id":"6c23a421.ca6f3c","type":"comment","z":"7061841b.7dc20c","name":"","info":"","x":140,"y":160,"wires":[]},{"id":"5c26c6e1.7c68d8","type":"inject","z":"7061841b.7dc20c","name":"{\"sobject\":\"Account\"}","topic":"","payload":"{\"sobject\":\"Account\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":220,"wires":[["722eb5e5.bc948c"]]},{"id":"722eb5e5.bc948c","type":"sf-universal-describe","z":"7061841b.7dc20c","name":"","sfconn":"73000fb4.ffb8e","api":"soap","describeAll":false,"objectName":"payload.sobject","objectNameType":"msg","target":"payload.describe","x":420,"y":220,"wires":[["c941c43f.b7d5b8"]]},{"id":"c941c43f.b7d5b8","type":"debug","z":"7061841b.7dc20c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":640,"y":220,"wires":[]},{"id":"73000fb4.ffb8e","type":"sf-connection-emitter","z":"","host":"SF_HOST","hostType":"env","username":"SF_USERNAME","usernameType":"env","password":"SF_PASSWORD","passwordType":"env","token":"","tokenType":"env"}]

Screenshot of universal describe

Name Type Description Example
Name String Label to show in Node Red Editor PE Subscription
Connection connection.SfConnectionEmitter The connection emitter configuration to use sfconn
Describe All boolean Whether to describe everything (true) or only an sobject (false) false
SObject Name string API Name of the SObject to describe Account
Target String The path within the message to put the results payload.results

http.SfUniversalHttp

Use this to perform an HTTP Get request to salesforce.

This is quite often used with the Universal Describe to get further information.

(Note: A common example is to use node-red-contrib-literal-utils to pick the urls from a set of describes, and then use node-red-contrib-serial-iterator to then iterate through each of those values and get the results)

NOTE: Currently, we are only supporting GET. If others factors are needed, please submit an issue and it can be discussed.

Example Flow

[{"id":"d2048d63.a9936","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"b684172.c49dfe8","type":"debug","z":"d2048d63.a9936","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":510,"y":200,"wires":[]},{"id":"67520728.547d28","type":"inject","z":"d2048d63.a9936","name":"{\"url\":\"/services/data/v42.0/sobjects/Account/describe\"}","topic":"","payload":"{\"url\":\"/services/data/v42.0/sobjects/Account/describe\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":270,"y":120,"wires":[["75031448.d6721c"]]},{"id":"75031448.d6721c","type":"sf-universal-http","z":"d2048d63.a9936","name":"","sfconn":"73000fb4.ffb8e","url":"payload.url","urlType":"msg","target":"payload","x":280,"y":200,"wires":[["b684172.c49dfe8"]]},{"id":"73000fb4.ffb8e","type":"sf-connection-emitter","z":"","host":"SF_HOST","hostType":"env","username":"SF_USERNAME","usernameType":"env","password":"SF_PASSWORD","passwordType":"env","token":"","tokenType":"env"}]

Screenshot of universal http

Example Flow with Repeater

A great example of using the http callout is if you have a list of URLs - such as templated from a previous describe...

[{"id":"c9dd3425.d23d88","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"f9b2421e.23d19","type":"inject","z":"c9dd3425.d23d88","name":"{\"urls\":[...]}","topic":"","payload":"{\"urls\":[\"/services/data/v42.0/sobjects/Account/describe/compactLayouts\",\"/services/data/v42.0/sobjects/Account/describe/approvalLayouts\",\"/services/data/v42.0/sobjects/Account/listviews\",\"/services/data/v42.0/sobjects/Account/describe\",\"https://speed-inspiration-3102-dev-ed.cs69.my.salesforce.com/001/e\",\"/services/data/v42.0/sobjects/Account/quickActions\",\"/services/data/v42.0/sobjects/Account/describe/layouts\",\"/services/data/v42.0/sobjects/Account\"]}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":140,"wires":[["f0240db8.37fa9"]]},{"id":"f0240db8.37fa9","type":"Serial Iterator","z":"c9dd3425.d23d88","name":"Serial Iterator","property":"payload.urls","inputFlow":"feedback","saveOutput":1,"recursive":0,"storeId":0,"x":320,"y":140,"wires":[["c545ae04.d3d54"],["36d218df.df27e8"]]},{"id":"c545ae04.d3d54","type":"sf-universal-http","z":"c9dd3425.d23d88","name":"","sfconn":"73000fb4.ffb8e","url":"payload","urlType":"msg","target":"payload","x":320,"y":220,"wires":[["f0240db8.37fa9"]]},{"id":"36d218df.df27e8","type":"debug","z":"c9dd3425.d23d88","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":550,"y":140,"wires":[]},{"id":"73000fb4.ffb8e","type":"sf-connection-emitter","z":"","host":"SF_HOST","hostType":"env","username":"SF_USERNAME","usernameType":"env","password":"SF_PASSWORD","passwordType":"env","token":"","tokenType":"env"}]

Screenshot of http with serial

Example Flow with Describe and Repeater

(Note: A common example is to use node-red-contrib-literal-utils to pick the urls from a set of describes, and then use node-red-contrib-serial-iterator to then iterate through each of those values and get the results)

[{"id":"833f466c.8e4288","type":"tab","label":"Simple Flow","disabled":false,"info":""},{"id":"9694019f.d3cb7","type":"inject","z":"833f466c.8e4288","name":"Blank Payload","topic":"","payload":"{}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":80,"wires":[["abe1fcd2.d03e5"]]},{"id":"abe1fcd2.d03e5","type":"sf-universal-describe","z":"833f466c.8e4288","name":"","sfconn":"73000fb4.ffb8e","api":"soap","describeAll":true,"objectName":"","objectNameType":"msg","target":"describe","x":340,"y":80,"wires":[["740e1493.83e07c","3de2ebf4.276014"]]},{"id":"740e1493.83e07c","type":"debug","z":"833f466c.8e4288","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":550,"y":40,"wires":[]},{"id":"55cc2fc3.d9035","type":"debug","z":"833f466c.8e4288","name":"Complete","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":360,"y":420,"wires":[]},{"id":"c73609ff.5022c8","type":"Serial Iterator","z":"833f466c.8e4288","name":"","property":"describe.urls","inputFlow":"feedback","saveOutput":1,"recursive":0,"storeId":0,"x":130,"y":300,"wires":[["7bcef9d2.ed5e48"],["55cc2fc3.d9035"]]},{"id":"7bcef9d2.ed5e48","type":"sf-universal-http","z":"833f466c.8e4288","name":"","sfconn":"73000fb4.ffb8e","url":"payload","urlType":"msg","target":"payload","x":370,"y":300,"wires":[["c73609ff.5022c8"]]},{"id":"e5f2e6e5.3be2c8","type":"comment","z":"833f466c.8e4288","name":"Describe the list of objects...","info":"","x":160,"y":40,"wires":[]},{"id":"de2df7bd.d94808","type":"function","z":"833f466c.8e4288","name":"Only describe the first 3 urls","func":"msg.describe.urls = msg.describe.urls.slice(0,3);\nreturn msg;","outputs":1,"noerr":0,"x":380,"y":200,"wires":[["6db56361.e766dc","c73609ff.5022c8"]]},{"id":"3de2ebf4.276014","type":"pick-array-value","z":"833f466c.8e4288","name":"","arrayPath":"describe.sobjects","valuePath":"urls.sobject","targetPath":"describe.urls","x":150,"y":200,"wires":[["de2df7bd.d94808"]]},{"id":"6db56361.e766dc","type":"debug","z":"833f466c.8e4288","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":590,"y":160,"wires":[]},{"id":"5fcec93a.536a38","type":"comment","z":"833f466c.8e4288","name":"Pick the URLs from the array of objects...","info":"","x":200,"y":160,"wires":[]},{"id":"a758b017.2a287","type":"comment","z":"833f466c.8e4288","name":"Loop through the URLs one at a time...","info":"","x":210,"y":260,"wires":[]},{"id":"73000fb4.ffb8e","type":"sf-connection-emitter","z":"","host":"SF_HOST","hostType":"env","username":"SF_USERNAME","usernameType":"env","password":"SF_PASSWORD","passwordType":"env","token":"","tokenType":"env"}]

Screenshot of describe and repeater

Properties

Name Type Description Example
Name String Label to show in Node Red Editor Universal Describe
Connection connection.SfConnectionEmitter The connection emitter configuration to use sfconn
URL (Message property |
Global Setting |
Environment Variable |
Literal Value)
URL to request Payload (ex: serial)
-OR-
Payload.url
-OR-
/services/data/v42.0/sobjects/Account/describe
-OR-
https://speed-inspiration-3102-dev-ed.cs69.my.salesforce.com/001/e
Target String The path within the message to put the results payload.results



Extending

While the request to use ES6 classes is currently underway within Node-Red modules, the following is the current structure for the nodes:

All nodes can be found by importing the module:

Note that Node-Red gets access to the setupNodeRed function, using require(...) directly gives access to the es6 class.

Also note, although NodeRed does not support TypeScript, care has been taken to support jsdoc / intellisense - to make extending these modules easier...

Screenshot of intellisense

connection.SfConnectionReceiver

Base Class for many of the other commands.

Note that this provides a couple convenience functions, such as setting the status and base methods for listening to newConnection and connectionLost events.

Simply override the handleNewConnection(JsForceConnection) and handleConnectionLost(JsForceConnection) methods - respectively...

Properties

Name Type Description Example
RED @types/node-red#Red Node Red instance - captured during initialization
config object Configuration passed to the node from the node red editor {name:'query',query:'...'}
nodeRedNode @types/node-red#Node Node Red Node instance to be manipulated
connectionEmitter Node Red Config Id The connection emitter configuration to use sfconn
STATUS_CONNECTED string Use this with the #status(string) command to set the status on the node
STATUS_DISCONNECTED string Use this with the #status(string) command to set the status on the node

initialize

Intitialize the node

Name Type Description Example
RED @types/node-red#Red Node Red instance - captured during initialization
config object Configuration passed to the node from the node red editor {name:'query',query:'...'}
nodeRedNode @types/node-red#Node Node Red Node instance to be manipulated

Returns the instance, to support chaining...

listenToConnection

Starts listening to a single salesforce connection emitter...

Just give it the name of the property on the connection that holds the value, it will figure out the rest.

Name Type Description Example
connectionPropName String The property of the connection to check the value for sfconn

Returns void

setStatus

Sets the status on the node

Name Type Description Example
status string STATUS_CONNECTED|STATUS_DISCONNECTED

Sets the status on the node so it appears connected or disconnected...

Screenshot of connected node

handleNewConnection

Overwrite this method to get notified when a connection is established.

(note that existing connections can be compared and so can also be disconnected, or see handleConnectionLost method below)

Name Type Description Example
connection JSForce.Connection The new connection established

handleConnectionLost

Overwrite this method to get notified when the connection is lost.

(This will always get called before handleNewConnection on a connectionEmitter#refresh event)

Name Type Description Example
connection JSForce.Connection The new connection established

Subclassing

For example: to access the ConnectionReceiver (for subclassing), use the following:

const connectionEmitter = require('node-red-contrib-salesforce-connection-emitter');
const SfConnectionReceiver = connectionEmitter.connection.SfConnectionReceiver;
//-- or directly through destructuring
const {connection: {SfConnectionReceiver}} = require('node-red-contrib-salesforce-connection-emitter');

class MyClass extends SfConnectionReceiver {...}

one further example - changing the name of the class:

const {connection: {SfConnectionReceiver:ConnectionReceiver}} = require('node-red-contrib-salesforce-connection-emitter');

class MyClass extends ConnectionReceiver {...}

Running Tests

  • To test the project run npm run test or npm run test:watch to continuously test.

Running Linter

  • To run linters on the project, run npm run lint or npm run lint:watch to continously lint.

Further

Node Info

Version: 1.4.3
Updated 6 years, 2 months ago
License: MIT
Rating: not yet rated

Categories

Actions

Rate:

Downloads

35 in the last week

Nodes

  • sf-connection-emitter
  • sf-platform-event-pub
  • sf-platform-event-sub
  • sf-universal-query
  • sf-universal-describe
  • sf-universal-http

Keywords

  • salesforce
  • platform-events
  • node-red
  • jsforce
  • publish
  • subscribe
  • platform
  • event

Maintainers