Dynamically Execute Apex Script in Salesforce Flow
Hi Folks!
As a flow developer you may get annoyed by the fact that you have to write Apex, write Apex Test, and deploy your Apex everytime you want to have functionality that flow does not have but apex has, especially if you only need a small functionality from the Apex itself. But what if, you can write your apex script and execute that apex script on the fly with only a single variable in Flow?
Invocable Execute Apex Script
Invocable Execute Apex Script is an invocable method (an Apex function that you can access in flow) that can help you to execute your Apex script dynamically on the fly within Flow. Magic behind this flow action is you do a callout to Salesforce Execute Anonymous Apex API with the Apex Script that you pass to the input.
Input Attributes
- Apex Script (Required)
This is an Apex Script you would like to execute. You can use Text Template to formulate the Apex Script and pass some variables to the text template(just make sure it’s in plain text mode)
API Name : apexScript
Type : Text / String
Example : System.debug(‘Hello World’); - API Version (Optional)
This is the API Version of the Apex Script you’d like to execute. If none, will be defaulted to v59.0
API Name : apiVersion
Type : Text / String
Example : v59.0 - Named Credential API Name (Optional)
This is the Named Credential you’d like to use for the callout. If you don’t set the Named Credential, it will use the running user’s context auth token by using UserInfo.getSessionId(). Here’s the how-to create Named Credential for Tooling API. Here are the extended functionality you can have if you use Named Credential
- You can do the callout synchronously, which means you can know immediately whether you script is sucessfully executed or not. Check when to run asynchronously or synchronously on image05.
- If the user that will run this Flow Action does not have Execute Anonymous Apex Permission and you set the Named Credential Auth Provider to Named Principle (authenticated as a System Admin user), your user will still be able to run this Flow Action. But the user context will be as the System Admin user.
API Name : namedCredentialApiName
Type : Text / String
Example : Tooling_API - Run Asynchronously ? (Optional)
If set to true, the callout will run asynchronously using Queueable Apex and you won’t be able to know the result of the script execution immediately. If Named Credential is empty, this will be automatically defaulted to True. If Named Credential is not empty, automatically defaulted to False. The output of Run Asynchronously will only be the Job Id of the Queueable.
API Name : runAsynchronously
Type : Boolean
Example : True
Output Attributes
- (Async) Job ID
Only output in Asynchronous mode. This is a Job ID that you will retrieve if you run this action asynchronously. You can check the result of your apex script execution in Apex Jobs list view.
API Name : jobId
Type : Text / String
Example : 7075g00008hIm63 - (Sync) Line
Only output in Synchronous mode. Represents the line number in the code where a particular event or issue occurred during the execution. This can be useful for pinpointing the location of errors or other events.
API Name : column
Type : Number / Integer
Example : -1 - (Sync) Column
Only output in Synchronous mode. Represents the column number in the code where a particular event or issue occurred during the execution. Similar to line, it helps narrow down the location of errors or events.
API Name : column
Type : Number / Integer
Example : -1 - (Sync) Compiled
Only output in Synchronous mode. A Boolean flag indicating whether the Apex code was successfully compiled (true) or if there were compilation errors (false). If compiled is false, you might check the compileProblem for details on the compilation issue.
API Name : compiled
Type : Boolean
Example : True - (Sync) Success
Only output in Synchronous mode. A Boolean flag indicating the overall success of the execution. If success is true, the execution was successful; if false, there might be issues that need attention.
API Name : success
Type : Boolean
Example : True - (Sync) Compile Problem
Only output in Synchronous mode. If the code compilation fails, this variable provides details about the specific problem encountered during compilation. It typically includes an error message indicating what went wrong in the code.
API Name : compileProblem
Type : Text / String
Example : Unexpected token ‘=’ - (Sync) Exception Stack Trace
Only output in Synchronous mode. In case of runtime exceptions or errors during execution, this variable contains the stack trace associated with the exception. The stack trace gives a detailed report of the sequence of calls and the point at which the exception occurred.
API Name : exceptionStackTrace
Type : Text / String
Example : AnonymousBlock: line 1, column 1 - (Sync) Exception Message
Only output in Synchronous mode. Provides a human-readable message associated with any runtime exception that occurred during execution. It summarizes the nature of the exception or error.
API Name : exceptionMessage
Type : Text / String
Example : System.MathException: Divide by 0
Deciding when to run asynchronously or synchronously
How to check status of the Asynchronous Job
- Go to Setup -> Search for Apex Jobs -> click Apex Jobs
- Click Create a New View
- Name it InvocableExecuteApexScript
- Set Apex Class Name Equal to InvocableExecuteApexScript as a filter
- Click Save
- Search the job based on Job ID that being outputted in the Flow
- Check column Status Detail
Sample Use Case : Force Pause / Wait in Record Triggered Flow
Let’s try to find a workaround for this idea. Disclaimer : The solution I give you probably won’t be a best practice, but just to give you a clear idea on how you can actually achieve this.
Step 1 — Prepare an Autolaunched Flow with Wait element
Step 2 — Prepare an Apex Script to Launch that Autolaunched Flow (You can try it first in Anonymous Apex Window)
String inputVariableName = 'recordId'; //input variable name in the subflow
String recordId = '{!$Record.Id}'; //value of the variable in the subflow
String flowName = 'Force_Pause'; //api name of the subflow
Map<String,Object> inputVariablesMap = new Map<String,Object>();
inputVariablesMap.put(inputVariableName,recordId);
Flow.Interview myFlow = Flow.Interview.createInterview(flowName,inputVariablesMap);
myFlow.start();
Step 3— Prepare a record triggered flow that will trigger the Autolaunched Flow
Step 4 — Test and Validate
Consideration and Limitation :
- With great power comes great responsibility, whoever user context that will do the callout should have Apex Author permission enabled, you can consider to use Named Principle Named Credential.
- This will consume more of your API Call limit (and Apex Async Limit if you do it asynchronously) since this solution require a callout.
- You should ensure that the script does not inject any variable that you dont intend, else it may become a security issue.
Installation
Please clap if you think this is useful. Let me know if you have any question. Thank you