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

  1. Node.js LTS
  2. Yarn package manager
  3. The latest version of the Salesforce CLI: sfdx update
  4. 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.

Screenshot showing the plug-in generation output

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:

Screenshot showing the command generation output and its generated files

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 like directory, 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 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 application/json or application/xml)
  • 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:

  1. We can create a connection using the AuthInfo and Connection classes from the @salesforce/core library. For that, we would need the org username (or alias), which will be provided by the target-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

About the author

Julian Duque

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.

Get the latest Salesforce Developer blog posts and podcast episodes via Slack or RSS.

Add to Slack Subscribe to RSS