node-salesforce-connection is a minimal library for connecting to Salesforce from Node.js. It provides an absolute minimal wrapper that allows you to call any Salesforce API. It tries hard to not get in the way between you and Salesforce. It has no dependencies.
This library works in Node.js. There is an almost identical library that works in browsers, but that it not yet published as a stand-alone package.
This documentation explains how the node-salesforce-connection library works, but you need to read this in combination with the official Salesforce API documentation, since this document does not explain how the Salesforce APIs themselves work.
Create your own project using npm init
and then add this library as a dependency using npm install node-salesforce-connection --save
.
Use it like this in your JS file:
let SalesforceConnection = require("node-salesforce-connection");
(async () => {
let sfConn = new SalesforceConnection();
await sfConn.soapLogin({
hostname: "login.salesforce.com",
apiVersion: "39.0",
username: "[email protected]",
password: "MyPasswordMySecurityToken",
});
let recentAccounts = await sfConn.rest("/services/data/v39.0/query/?q="
+ encodeURIComponent("select Id, Name from Account where CreatedDate = LAST_WEEK"));
for (let account of recentAccounts.records) {
console.log("Account " + account.Name + " was created recently.");
}
})().catch(ex => console.error(ex.stack));
The examples use the JavaScript await
keyword.
This assumes the examples are placed in an async function like the one above.
You don't have to use async functions, if you prefer using the traditional promise.then(handler)
syntax.
The first thing you need to do is log in to Salesforce.
You can use the soapLogin
function to log in using a username and password:
let sfConn = new SalesforceConnection();
await sfConn.soapLogin({
hostname: "login.salesforce.com",
apiVersion: "39.0",
username: "[email protected]",
password: "MyPasswordMySecurityToken",
});
The function calls the SOAP login method.
The function returns a promise
that behaves identically to the promise returned from the soap
function.
When the promise resolves successfully, sfConn
will be ready to use.
You can log in using OAuth. Here is an example of the Username-Password OAuth Authentication Flow:
let sfConn = new SalesforceConnection();
let tokenRequest = {
grant_type: "password",
client_id: "MyConsumerKey",
client_secret: "MyConsumerSecret",
username: "[email protected]",
password: "MyPasswordMySecurityToken",
};
let hostname = "login.salesforce.com";
await sfConn.oauthToken(hostname, tokenRequest);
The function makes a POST
request to /services/oauth2/token
.
The function returns a promise
that behaves identically to the promise returned from the rest
function.
When the promise resolves successfully, sfConn
will be ready to use.
Use the oauthToken
function with the
Web Server,
Username-Password and
Refresh Token
OAuth authentication flows. Use the manual approach described below for the User-Agent flow.
If SOAP or OAuth login does not work for you, you can manually initialize the connection with your own questionably obtained session information:
let sfConn = new SalesforceConnection();
sfConn.instanceHostname = "na1.salesforce.com";
sfConn.sessionId = ".....";
The best way to make API calls is using any Salesforce REST API. Use for example the Bulk, Chatter, REST, Tooling or Reports and Dashboards API.
Example using query:
let recentAccounts = await sfConn.rest("/services/data/v39.0/query/?q="
+ encodeURIComponent("select Id, Name from Account where CreatedDate = LAST_WEEK"));
for (let account of recentAccounts.records) {
console.log("Account " + account.Name + " was created recently.");
}
Example creating a record:
let myNewAccount = {Name: "test"};
let result = await sfConn.rest("/services/data/v39.0/sobjects/Account",
{method: "POST", body: myNewAccount});
console.log("Created Account with ID " + result.id
+ (result.success ? " successfully." : " failed."));
The rest
function accepts the following parameters:
sfConn.rest(path, {method, api, body, bodyType, headers, responseType});
Parameter | Type | Default | Description |
---|---|---|---|
path
| string | (required) | A path relative URL to request. E.g. /path/to/resource?param=value&other=two .
|
method
| string | "GET"
| The HTTP method to use. |
api
| string | "normal"
|
The type of REST API.
|
body
| Depends on bodyType
| (none) | Used as the HTTP request body, formatted according to the bodyType parameter.
|
bodyType
| string | "json"
|
Indicates the type of the body parameter.
|
headers
| object | (none) |
A JavaScript object of additional HTTP headers.
Example: {"Sforce-Query-Options": "batchSize=1000"} .
|
responseType
| string | "json"
|
Indicates the type of the HTTP response body.
|
The rest
function returns a promise.
If the request succeeds, the promise will resolve with the HTTP response parsed according to the responseType
parameter.
If the request fails because Salesforce returned an error response (such as HTTP 400), the promise will reject with an Error
with these properties:
Property name | Type | Value |
---|---|---|
name
| string | "SalesforceRestError"
|
message
| string | A descriptive error message. A text version of the detail property, or the HTTP status message if we did not receive a HTTP response body.
|
detail
| Depends on responseType
| The HTTP response body parsed according to the responseType input parameter.
|
response
| SalesforceResponse
| An object containing the HTTP response headers, response status and binary response body. |
If the request fails because Node.js could not connect to Salesforce, the promise will reject with a Node.js System Error.
A SalesforceResponse
object has these properties:
Property name | Type | Value |
---|---|---|
headers
| object | The HTTP response headers. |
statusCode
| number | The 3-digit HTTP response status code. E.g. 404 .
|
statusMessage
| string | The HTTP response status message (reason phrase). E.g. OK or Internal Server Error .
|
body
| Node.js Buffer | The HTTP response body. Call response.body.toString() to get the response body as text.
|
If the functionality you are looking for is not available via any of the Salesforce REST APIs, you might be able to find a Salesforce SOAP API that does what you need. However, this being JavaScript, you should probably avoid SOAP when possible.
Example using upsert:
let enterpriseWsdl = sfConn.wsdl("39.0", "Enterprise");
let contacts = [
{$type: "Contact", FirstName: "John", LastName: "Smith", Email: "[email protected]"},
{$type: "Contact", FirstName: "Jane", LastName: "Smith", Email: "[email protected]"},
];
let upsertResults = await sfConn.soap(enterpriseWsdl, "upsert",
{externalIdFieldName: "Email", sObjects: contacts});
for (let r of sfConn.asArray(upsertResults)) {
console.log((r.created == "true" ? "Created" : "Updated")
+ " Contact with ID " + r.id + " "
+ (r.success == "true" ? "successfully" : "failed") + ".");
}
Before you make a SOAP API request, you need a WSDL, which you get using the wsdl
function.
Well, you don't actually get the full WSDL file.
You only get the absolute minimum information needed to make SOAP API calls from JavaScript.
The wsdl
function accepts the following parameters:
sfConn.wsdl(apiVersion, apiName);
Parameter | Type | Default | Description |
---|---|---|---|
apiVersion
| string | (required) | The Salesforce API version you want to use. |
apiName
| string | (required) |
The Salesforce SOAP API you want to use. Supported values are
"Enterprise" ,
"Partner" ,
"Apex" ,
"Metadata" and
"Tooling" .
|
The wsdl
function returns an object containing information from the WSDL that is needed to make SOAP requests.
Alternatively, you can call the wsdl
function with only one parameter to get an object with all the WSDL's we know:
let wsdlSet = sfConn.wsdl(apiVersion);
let myWsdl = wsdlSet[apiName];
With the WSDL information at hand, you can make your SOAP API request using the soap
function.
The soap
function accepts the following parameters:
sfConn.soap(wsdl, method, args, {headers});
Parameter | Type | Default | Description |
---|---|---|---|
wsdl
| object | (required) |
An object containing information from the WSDL that is needed to make SOAP requests.
You can either obtain this object by calling sfConn.wsdl or create the object manually.
|
method
| string | (required) | The SOAP method to be called, as found in the Salesforce documentation. The example above uses upsert. |
args
| object | (required) | The arguments to the called SOAP method, as found in the Salesforce documentation. Pass an object where each property corresponds to a SOAP method argument by name. Pass an empty object if the method does not require any arguments. |
headers
| object | (none) |
An optional object with Salesforce SOAP headers.
Pass an object where each property corresponds to a SOAP header by name.
The Salesforce Session ID is automatically added here, so you don't have to.
Example: {AllOrNoneHeader: {allOrNone: false}, EmailHeader: {triggerAutoResponseEmail: true}} .
|
sObjects are a bit special in the SOAP API. You always need to specify the type of an sObject.
In the Partner WSDL, use the type
property (Example: {type: "Account", Name: "Example"}
).
In the Enterprise WSDL and others, use the $type
property (Example: {$type: "Account", Name: "Example"}
).
The soap
function returns a promise.
If the request succeeds, the promise will resolve with the SOAP method's return value.
When you get the return value from a SOAP API call, you won't get the precise type of the returned data, since that information is only available in the WSDL. You have to convert the type yourself using these rules:
- If you expect a string, you will get a string.
- If you expect a number, you will get a string. Convert it to a number using for example
let myNumber = Number(myValue)
. - If you expect a boolean, you will get a string. Convert it to a boolean using for example
let myBoolean = myValue == "true"
. - If you expect null, you will get null.
- If you expect an object, you will get an object.
- If you expect an array, you will get different things if your array has zero, one or more elements. Convert it to an array using the
asArray
utility function, for examplelet myArray = sfConn.asArray(mvValue);
.
If the request fails because Salesforce returned a SOAP fault,
the promise will reject with an Error
with these properties:
Property name | Type | Value |
---|---|---|
name
| string | "SalesforceSoapError"
|
message
| string | A descriptive error message. The faultstring part of the SOAP fault message returned by Salesforce.
|
detail
| object | The SOAP fault message returned by Salesforce. |
response
| SalesforceResponse
| An object containing the HTTP response headers, response status and binary response body. |
If the request fails because Node.js could not connect to Salesforce, the promise will reject with a Node.js System Error.
The rest
and soap
functions return promises you can use in error handling like any other promise.
Example:
try {
let result = await sfConn.rest("/services/data/v39.0/query/?q="
+ encodeURIComponent("select Id from UnknownObject"));
console.log(result);
} catch (ex) {
if (ex.name == "SalesforceRestError") {
console.log("Salesforce returned an error: " + ex.message);
} else if (ex.syscall == "getaddrinfo") {
console.log("Could not make request. Are you offline?");
} else {
throw ex; // Unknown type of error
}
}
Same example with an older JavaScript syntax:
sfConn.rest("/services/data/v39.0/query/?q="
+ encodeURIComponent("select Id from UnknownObject"))
.then(function(result) {
console.log(result);
}, function(ex) {
if (ex.name == "SalesforceRestError") {
console.log("Salesforce returned an error: " + ex.message);
} else if (ex.syscall == "getaddrinfo") {
console.log("Could not make request. Are you offline?");
} else {
throw ex; // Unknown type of error
}
});
Before I made this library, I used JSForce. It is a nice library, but I ran into a few bugs, and I needed a specific new Salesforce APIs that was not yet added to JSForce at the time. So I made this library instead, which aims to give you access to any current or future Salesforce API without needing to update the library. It aims to provide 95% of the convenience for 5% of the size/complexity.