@dynau/sf-utils
v1.0.8
Published
wrappers for Salesforce REST APIs
Downloads
4
Readme
@dynau/sf-utils
Provides convenient JS/TS wrappers for basic Salesforce REST APIs.
For assistance reach out to author - Anton Dynau.
What's included:
- Apex
- execute anonymous apex
- Bulk API
- Ingest
- execute full job & return results
- single operations:
- create job
- upload job data
- finalize data upload
- get job status
- await completion
- get successful results
- get failed results
- Query
- execute full job & return results
- single operations:
- create job
- get job status
- await completion
- get job results
- Ingest
- Sobject
- get record count
- Record
- all DML operations
- Collection
- all DML operations
- Soql
- execute soql query
- TS type generation
- generate type for CSV
- generate type for Sobject
General Concepts
Design
All actions that you can perform work with the same arguments:
- target org alias
- action config - parameters specific to each action
- log config - if provided, will output information about action progress into console
await Salesforce.doSomething(
"your-org-alias",
{ paramA: 3.14, paramB: false },
{ actionName: "doSomething", logLevel: "ANNOUNCE" }
);
Static vs instance usage
You have 2 ways to use the library:
- Static methods of
Salesforce
class
await Salesforce.Apex.executeAnonymous("org-alias", {
anonymousBody: "System.debug('hello');",
});
- create an instance of Salesforce
const MY_ORG = new Salesforce("org-alias");
await MY_ORG.Apex.executeAnonymous({
anonymousBody: "System.debug('hello');",
});
The 2 options are identical in result, Salesforce instance can be duplicated if needed - it does not store any callout results, it's only purpose is to pass pre-populated org alias and log config to function calls
Authentication
All authentication is handled under the hood via SF CLI based on proviede targetOrg
parameter. You can pass either an org alias or a username for one of orgs authenticated on your machine (run sf org list
in terminal to see the list of orgs)
I understand that different people have different org aliases and usernamed for the same org, so to make it possible for multiple people to use the same codebase with hardcoded org aliases, I implemented a config system for this library.
Instance URL, resource URL, resource parameters etc.
The library handles all technical details of rest callouts and more, including:
- Salesforce instance URL
- REST resource URL
- REST resource API version
- REST resource bodies
- REST resource URL parameters
- REST resource headers
You just pass all action-specific parameters as function arguments, and they are applied in a context-aware manner. For exaple, the URL for this callout:
Salesforce.Sobject.Record.get("your-org-alias", {
sObjectName: "Account",
fields: ["Id", "Name"],
recordId: "0010700000oq6XHAAY",
});
... will be:
Notice how the url got an API version auto-populated, sobject name & record id populated from function arguments, and a list of fields appended as query parameters
Caching
Some data is either cached at runtime or stored locally as files to reduce the amount of callouts and execution time
Here's the list of all caches:
- org connection info is runtime-cached (
sf org display
is only called once per JS execution for each unique org alias) - sobject list callouts are runtime-cached (executed only once per JS execution for each org and scope - regular sobjects of tooling sobjects)
- sobject schema is both runtime-cached and stored as json file cache. Any request to retrieve object schema follows this logic:
- if schema is already loaded in runtime, return it
- else if it's present in file storage, parse the json file and return contained schema*
- else perform callout to retrieve schema and store it locally
Library config
Config file is not necessary for the library to work, but it allows you to change the default locations for storage of some files and map one org alias to another
Config file should be located at the root of the project and be named sf-utils-config.json
.
Config has the following structure:
{
"sobjectSchemaStoragePath": "./sobject-schema-storage", // default value
"generatedTypesPath": "./generated-types", // default value
"orgAliasReplacements": [
{
"enteredValue": "[email protected]",
"resultValue": "[email protected]"
}
]
}
Action examples
Execute anonymous apex
Used resource: /services/data/vXX.X/tooling/executeAnonymous/
If createTraceFlag == true
, debug logs will be generated as if the user was executing the code in dev console. Otherwise the logs will not be generated.
await Salesforce.Apex.executeAnonymous("sf-org-alias", {
apex: "System.debug(Date.today());",
createTraceFlag: true, // simulates your user opening dev console
});
/*
=> {
line: -1,
column: -1,
compiled: true,
success: true,
compileProblem: null,
exceptionStackTrace: null,
exceptionMessage: null
}
*/
Bulk API Ingest
Opinions
This library is opinionated in some aspects:
- allOrNone -- DML actions that deal with Sobject collections have a "allOrNone" parameter. Salesforce REST APIs treat is as optional and
false
by default. In this library it's the other way round -- the parameter is still optional, but istrue
by default, meaning that it will treattrue
or=== undefined
astrue
. In other words, transaction logic is close to Apex. - Callout results -- any action that fails will throw a native JS error that you can process in a try-catch block. Notable exceptions from this list are actions working with Sobject collection that have
allOrNone
flag. In this case no error will be thrown so that you could iterate over returned DML results and process record-level errors yourself (also Salesforce itself considers callout successful even if all records fail even withallOrNone = true
) - Datatypes of Sobject fields are type-casted in all actions to provide consistency between different sources and APIs (CSV vs JSON, BULK API v2 vs sogject/get)