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.
- Node.js LTS
- Yarn package manager
- The latest version of the Salesforce CLI:
- 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.
@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
|npm file that describes package dependencies and versions.
|Main TypeScript file that contains the code for the rest command. The command imports and extends classes from @salesforce/sf-plugins-core.
|Markdown file that contains the messages that make up the command help and errors.
|Complex integration, smoke, and end-to-end tests. Also known as NUTS (non-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
SfCommandclass from the
- Strings (messages) like the summary, description, examples, etc. are stored in markdown format and loaded using the
- Flags are defined with the
@salesforce/sf-plugins-core, this will give you more options for flags like
orgApiVersion, and others. More information about the available flags can be found in the documentation.
runmethod is where the command logic is executed. It is recommended to specify a return type, which will be used by the
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.
path— represents the path of the API resource (with or without the
target-org, o— represents the username or alias of the authenticated org
method, m— represents the HTTP method used to interact with the API
content-type, t— represents the Content-Type header of the request (either
payload, p— represents the request payload either in JSON or XML
api-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
Connectionclasses from the
@salesforce/corelibrary. For that, we would need the org username (or alias), which will be provided by the
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
The plug-in logic as shown above does the following:
- Extracts the org from the
- Gets the connection from the org using
org.getConnection(), which will return an authenticated connection object
- Sets the
apiVersionto the connection if the flag is specified
- Extracts the HTTP parameters from flags
- Performs the HTTP request using the
requestmethod from the connection object
- Prints the output as a styled JSON using the
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
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!
- 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.