Deliver Scalable Experiences Without Limits Using Functions | Salesforce Developers Blog

We’re proud to launch the Salesforce Functions Beta in our Summer ‘21 release, and we look forward to its GA in our Winter ’22 release.

Salesforce Functions is a new service on the Salesforce Platform that enables you to deliver more scalable experiences by extending the data and workflows that you already have, making them more robust with the power of elastic compute and open language flexibility. You can now significantly accelerate developer productivity on trusted, managed Salesforce infrastructure through pre-authenticated and preconfigured access to Salesforce data and integration with low-code tools like Flow.

Functions allows developers to write code that implements their business logic, which can then be assembled as building blocks in Flows or integrated with Lightning Web Components. Salesforce Functions amplifies low-code productivity with the power and flexibility of custom software, including access to open language ecosystems of libraries and packages.

Let’s take a deeper look into what this actually means, and along the way, we’ll show you the updated Developer Tools experience.

What’s new in the Salesforce Functions Beta

  1. Higher performance with no limits and elastic scale
    1. Build applications faster and without limits for more complex business logic or compute-intensive traffic/request activity. Salesforce Functions retains all the security and compliance you trust Salesforce to provide, so you no longer need to deal with VPNs, security tokens, Cloud IAM, and all the DIY complexity when you go off of the Salesforce Platform.
  2. Open languages and framework support in your SFDX project, including Java and Node.js
    1. Functions let you program in industry-standard languages, such as Node.js and Java. This brings the expressive power of these languages to your apps, as well as the entire ecosystem of tools, libraries, and developers to accelerate your time to market.
  3. Familiar tools and native low code integration
    1. Functions are fully integrated into the Salesforce Developer Experience and are invoked directly from Apex, making them easy to add to Flows and the simplest way to add complex business logic to your apps.
    2. One CLI for development
      1. The Salesforce CLI is being enhanced with a new global executable, sf, that simplifies how you build, manage, and deploy across Salesforce.

Functions use case: running compute heavy and high-performance workloads

In this blog post, we’re going to create a Java Function that processes a very large data set. Without Functions, it would be impossible to handle a data set this large in Apex, and many users would have had to implement complex workarounds to remain within their Apex limits. With Functions, you can overcome these kinds of computational limitations. In this example, the Function loads the complete six-thousand-record data set into memory.

In the following example, we will use Functions to find a code school that is closest to a specific geographic point. It will also iterate over the data set to calculate the distance from a point of origin, sorting the results by distance, and then returning the ones that are closer to the provided location.

This can be done in a few simple steps:

  1. Write a Function in an SFDX project
  2. Run and debug your Function locally to validate logic
  3. Deploy the Function to a Salesforce Org
  4. Integrate with low code: invoke the Function through Apex

Done – you’ve leveraged the compute capabilities from declarative tools.

Functions can be written in a Salesforce DX project by using the Salesforce CLI or Visual Studio Code editor with the Salesforce Extension Pack.

To create a project with this new command structure using the Salesforce CLI, run:

$ sfdx generate:project -n sfdx_functions_project

The Visual Studio Code editor with the Salesforce Extension Pack will create a project with the necessary files to start developing for the Salesforce Platform.

After creating the project, we can start writing our Functions, by using either Java or JavaScript.

Let’s generate the processlargedata function in Java with the Salesforce CLI:

$ sfdx generate:function -n processlargedata -l java

Or using the Visual Studio Code SFDX: Create Function command:

Generate a Function from Visual Studio Code

This will generate a Java project under the functions folder with all the necessary files to write your Function and run tests locally.

Let’s update the auto-generated Function with the use case we described above. The full source code for this project in the Functions Recipes Sample Application is available on Github.com.

package com.salesforce.functions.recipes;

// ...

/**
 * This function loads a large JSON dataset, calculates the distance between a supplied cordinate
 * and the data, sort's it and returns the nearest x results.
 */
public class ProcessLargeDataFunction implements SalesforceFunction<FunctionInput, FunctionOutput> {
  private static final Logger LOGGER = LoggerFactory.getLogger(ProcessLargeDataFunction.class);
  private static final String SCHOOLS_URL = "https://code.org/schools.json";

  @Override
  public FunctionOutput apply(InvocationEvent<FunctionInput> event, Context context)
      throws Exception {
    // Read Input Parameters
    // - Point of Origin
    double latitudeSt = event.getData().getLatitude();
    double longitudeSt = event.getData().getLongitude();
    // - Number of results to return
    int length = event.getData().getLength();

    // Read Schools JSON Database into memory from URL
    URL url = new URL(SCHOOLS_URL);
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("GET");
    connection.connect();
    BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    // Parse Schools JSON Dataset
    Gson gson = new Gson();
    JsonResponse response = gson.fromJson(reader, JsonResponse.class);

    // Calculate Distance from point of origin -> Sort by Distance -> Limit results
    List<School> schools =
        response.getSchools().stream()
            .map(
                school -> {
                  school.setDistance(
                      distance(
                          latitudeSt, longitudeSt, school.getLatitude(), school.getLongitude()));
                  return school;
                })
            .sorted(Comparator.comparingDouble(School::getDistance))
            .limit(length)
            .collect(Collectors.toList());

    LOGGER.info("Function successfully filtered {} schools", schools.size());

    return new FunctionOutput(schools);
  }
  
  // ...

A Java Salesforce Function receives two parameters:

  • an InvocationEvent that contains the input payload of the Function
  • the Context, which has access to the authenticated Salesforce Org and the SDK. (Note: Node.js Functions contains a 3rd parameter Logger, which is used for logging operations).

This ProcessLargeDataFunction receives a JSON payload with latitude, longitude, and length, and returns a list of the nearest schools to that starting point specified in the input payload. Now, let’s see how can we run this Function locally.

Running your first Function

A Salesforce Function can be executed locally by using the CLI, which is a useful way to develop and test your Function without deploying it to a Salesforce Org. Local execution can be also integrated with an authenticated Salesforce Org when doing the invocation. You can start this Function locally by running:

$ sfdx run:function:start

Or by using the Visual Studio Code SFDX: Start Function command:

Start a Function from Visual Studio Code

This will build and run the Function locally, and it will be ready to start receiving invocation requests.

A Function running locally from Visual Studio Code

Now that our Function is running locally, we will use a JSON payload to invoke the Function. Let’s create a payload.json in the function folder with the following information:

{
  "latitude": "36.169090",
  "longitude": "-115.140579",
  "length": 5
}

This payload information represents the point of origin and the number of results it will return. It will be received by the Function in the InvocationEvent object.

You can invoke the Function with this input payload from the CLI by running:

$ sfdx run:function --url=http://localhost:8080 --payload=@payload.json

Or, you can do this from Visual Studio Code by opening the payload.json file, and clicking on the Invoke CodeLens action:

Invoking a Function from Visual Studio Code with CodeLens

You have seen how to generate, run, and invoke your first Salesforce Function using the Salesforce Developer Tools. Now it is time to connect to a Salesforce Organization, create a compute environment, and deploy the Function.

Deploying your first Function

We have been able to run our Function locally thanks to the Salesforce Developer Tools, but the real power of Salesforce Functions comes when they are running in our serverless compute environment. Let’s deploy our Function to a Salesforce Organization. To do that, we need to create a Compute Environment and connect it to an Org by running:

$ sfdx env:create:compute -o connected_org_alias -a compute_env_alias

Then, we need to deploy our Salesforce project and Functions. The upcoming sf CLI will allow you to deploy your project metadata along with the Function in a single command. But until then, we have to do that using sfdx in two steps:

$ sfdx force:source:push
$ sfdx project:deploy:functions -o connected_org_alias

Now that our project is deployed, we can invoke the Function from Apex by using the new Function class:

functions.Function fn = functions.Function.get('sfdx_functions_project.processlargedata');
functions.FunctionInvocation invocation = fn.invoke('{"latitude": "36.169090", "longitude": "-115.140579", "length": 5}');
String jsonResponse = invocation.getResponse();
System.debug('Got response' + jsonResponse);

Triggering a Function with Apex from the Developer Console

Integrating your Function with low-code tools

Now that our Function can be invoked through Apex, we can integrate it with a Flow or Lightning Web Component. Let’s create an Apex class, FindCodeSchools.cls, that invokes the ProcessLargeData Function from a Flow. The full source code for this project in the Functions Recipes Sample Application repo is available on Github.com.

public with sharing class FindCodeSchools {
  @InvocableMethod(label='Find Schools')
  public static List<School> findSchools(List<Input> input) {
    Input payload = input.get(0);
    // Get a Reference of the ProcessLargeData Function
    functions.Function fn = functions.Function.get(
      'sfdx_functions_project.processlargedata'
    );
    // Invoke the ProcessLargeData Function
    functions.FunctionInvocation invocation = fn.invoke(
      JSON.serialize(payload)
    );
    String response = invocation.getResponse();
    // Serialize the Response into an Object
    Output output = (Output) JSON.deserialize(response, Output.class);
    return output.schools;
  }
  
  // ...
}

With this Apex class with an @InvocableMethod, we will create a new Flow that triggers this method as an Apex action and use the output as we see fit. You can also trigger the Function from an LWC component by using the @AuraEnabled annotation.


Invoke the FindSchools Apex Method from a Flow

As you can see below, we seamlessly integrate the power of the compute capabilities of Salesforce Functions with the low-code simplicity of Flow.

Flow integrated with a Salesforce Function

Learn more

We’re excited to see what you build using Salesforce Functions. Please nominate yourself for the Invite Beta.

About the authors

Julián Duque is a Lead Developer Advocate at Salesforce. Connect with him on Twitter @julian_duque.
Khushboo Goel is a Sr. Product Marketing Manager at Salesforce. Connect with her on Twitter @kgoel31.

Stay up to date with the latest news from the Salesforce Developers Blog

Subscribe