The Salesforce CLI is a powerful and essential tool for Salesforce development. It can be used not only to create and build applications, but also to create and manage orgs, import and export data, run tests, and function as an automation tool for multiple purposes. But one of the most powerful, and often overlooked, aspects of the CLI is its extensibility through plug-ins.
In this blog post, we’ll show you how to write a Salesforce CLI plug-in using the @salesforce/plugin-dev
generator for the sf
CLI. We’ll also cover how to connect to a Salesforce org using the libraries provided by the plug-in generator.
Prerequisites
- Node.js LTS
- Yarn package manager
- The latest version of the Salesforce CLI:
sfdx update
- Visual Studio Code with Salesforce Extensions (optional but recommended)
Also, you’ll need to install the @salesforce/plugin-dev
plug-in for the sf
CLI to start creating a new plug-in. You can do so by running:
Generating a plug-in
Let’s generate a new plug-in by running sf dev generate plugin
. This generator will ask you some questions:
- Whether or not the plug-in is an internal Salesforce plug-in
- Plug-in name
- Plug-in description
- Author information
- Code coverage % to enforce
As an example, we will create a REST API plug-in that will allow us to perform authenticated Salesforce REST API requests directly from the terminal. We won’t have to worry about authorization tokens, instance URLs, etc. — all of this will be taken care of by our plug-in.
Generating a command
A plug-in can be composed of a stand-alone command or multiple commands grouped by topics. Note that we covered a lot of ground on CLI application fundamentals in the Building a CLI Application with oclif blog post.
The @salesforce/plugin-dev
plug-in comes with a handy generator, and we can also generate commands by running:
Let’s see what files were created for the rest
command.
File | Description |
package.json | npm file that describes package dependencies and versions. |
src/commands/rest.ts | Main TypeScript file that contains the code for the rest command. The command imports and extends classes from @salesforce/sf-plugins-core. |
messages/rest.md | Markdown file that contains the messages that make up the command help and errors. |
test/commands/rest.nut.ts | Complex integration, smoke, and end-to-end tests. Also known as NUTS (non-unit-tests.) |
test/commands/rest.test.ts | Unit tests. |
For the purposes of this blog post, we will focus only on the src/commands/rest.ts
file. If you want to take a look at the project, the full source code is hosted on GitHub.
Some key parts of the previous code include:
- A command is extended from the
SfCommand
class from the@salesforce/sf-plugins-core
library. - Strings (messages) like the summary, description, examples, etc. are stored in markdown format and loaded using the
Messages
class. - Flags are defined with the
Flags
class from@salesforce/sf-plugins-core
, this will give you more options for flags likedirectory
,url
,requiredOrg
,orgApiVersion
, and others. More information about the available flags can be found in the documentation. - The
run
method is where the command logic is executed. It is recommended to specify a return type, which will be used by the--json
flag.
Implementing a Salesforce REST API command
The command that we want to implement will allow us to perform authenticated requests to the Salesforce REST API. Before implementing the logic, it is recommended to design how your plug-in will work. More information about how to design a plug-in can be found in the documentation.
Arguments
path
— represents the path of the API resource (with or without the/services/data/<apiVersion>/
prefix)
Flags
target-org, o
— represents the username or alias of the authenticated orgmethod, m
— represents the HTTP method used to interact with the APIcontent-type, t
— represents the Content-Type header of the request (eitherapplication/json
orapplication/xml
)payload, p
— represents the request payload either in JSON or XMLapi-version
— represents the Salesforce API version to use for the request (if not present, it will use the current default)
Connecting to a Salesforce org
There are two ways to connect to a Salesforce org:
- We can create a connection using the
AuthInfo
andConnection
classes from the@salesforce/core
library. For that, we would need the org username (or alias), which will be provided by thetarget-org
flag.
Fortunately, the @salesforce/sf-plugins-core give us better utilities for this. We can use the custom Flags.requiredOrg utility to retrieve the org by username or alias, and this will return an authenticated org object when the flags are parsed.
Using the Connection object
The Connection class extends from JSforce Connection, which means that you’ll be able to perform any operation supported by JSforce. For the purpose of this plug-in, we will use the request
method to perform raw HTTP requests to the Salesforce REST API. Note: JSforce is a powerful JavaScript library to develop Salesforce applications.
The plug-in logic as shown above does the following:
- Extracts the org from the
target-org
flag - Gets the connection from the org using
org.getConnection()
, which will return an authenticated connection object - Sets the
apiVersion
to the connection if the flag is specified - Extracts the HTTP parameters from flags
- Performs the HTTP request using the
request
method from the connection object - Prints the output as a styled JSON using the
this.styledJSON()
method
Note: Be sure to authenticate into an org using sf login org
before using the sf rest
plug-in.
And finally, you can link the plug-in with your local sf
installation by running:
And voila! Now you can use the plug-in and start performing Salesforce REST API requests using the sf
CLI.
What’s next?
Make sure to take a look at the big improvements coming to the Salesforce CLI, especially those related to plugin development being easier than ever.
Also, we didn’t cover how to write tests for a Salesforce plug-in, which will require its own blog post. Luckily, our friend and Lead Developer Advocate Mohith Shrivastava already presented a codeLive session where he taught how to test Salesforce CLI plug-ins using NUTs, and there will be a follow-up post that we will publish soon. Stay tuned, and happy coding!
Learning resources
- Documentation: Quick Introduction to Developing sf Plug-ins
- Blog: Building a CLI Application with oclif
- codeLive: How to Build a Salesforce CLI Plug-In
- Mini Hacks Solved: Build a Salesforce CLI plugin to invoke static methods of an Apex class
- Salesforce REST API Reference Guide
- rest-api example plugin
About the author
Julián Duque is a Principal Developer Advocate at Salesforce. He is a developer and educator and spends his time running TTRPG games online and playing and training his Mini Aussie, Cumbia, and his Sphynx kitten, Nefertiti.