apex Step Type Properties

Use to include custom Apex functionality in a dashboard to access Salesforce platform features that aren’t inherently supported in Analytics. For example, pull in data using any API, manipulate data using your Apex classes, or apply simple case statements or complex machine learning. You can even harness AppExchange for things like integrating Twitter with Analytics—all in a way that is familiar.

To set up an apex step, create an Apex class that returns data in a shape that Analytics can consume. And then define the step with the apex step type in the dashboard JSON. The step calls the Apex REST endpoint to return the data from the Apex controller class.

Like a soql step, the Apex controller can return tabular data. Unlike saql and soql step types, the apex step type doesn’t define the "strings", "numbers", and "groups" arrays. The Apex class response must declare these column types.

When you define an apex step, you can use a selection or results binding on the body parameter in the step JSON. You can also reference this step type in a results binding. This step type doesn’t support faceting. If you run a Analytics REST API query using an apex step, the query runs as the logged-in user. Each REST API query counts against the org’s API limits.

Note the following limitations with apex steps:

  • If you include dashboards in a package, apex steps aren’t included. You must migrate the Apex classes separately.
  • The Android mobile app doesn’t support this type of step.
Field Name Description
type Step type. Set to apex.
label Step label, which is primarily used for display in the dashboard designer user interface.
query Query that returns the results. Can consist of the following parameters:
body
Optional. Blob containing the input parameters needed by the Apex controller class.
path
Required. Specifies the class path and name of the Apex controller class.

apex Step

1"GetStockData": {
2    "query": {   
3        "body": {
4            "symbol": "CRM"
5        },
6        "path": "stocks"
7    },
8    "type": "apex"
9}

Example

You want to display real-time stock data from a website in your dashboard. You want to fetch the data from an external API and add logic to determine the time of day for each stock price. Here’s the goal for this dashboard.
The toggle in the dashboard allows you to choose a company, which filters the results in the table and chart, and changes the displayed stock symbol.

To create this dashboard, complete the following steps:

  1. Create the Apex controller class that gets the data from the stock website.
  2. Add the stock website to the allowed sites in Salesforce.
  3. Create the apex step in addition to the other dashboard widgets.

Create the Apex Class

Define the Apex controller class and methods that return the stock price for different companies over time.
  1. From setup, enter Apex Classes in the Quick Find box, and select Apex Classes.
  2. Click New.
    You can create new Apex classes from this page.
  3. Add the following code.
    1@RestResource(urlMapping='/stocks')
    2global with sharing class StocksRestController {
    3
    4    @HttpPost  
    5    global static String stocks() {
    6        ApexStepRequest stepRequest = new ApexStepRequest(new ApexStepRequest.Parameter[]{
    7            new ApexStepRequest.Parameter('symbol', ApexStepRequest.ParameterType.STRING_PARAM)
    8        });
    9
    10        // fetch some stock data
    11        HttpRequest request = new HttpRequest();
    12        Http http = new Http();
    13        // make sure this domain is whitelisted in the proxy
    14        request.setEndpoint('https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&interval=5min&apikey=1QRP8ATD7134OVMA&symbol='
    15            // default to CRM
    16            + stepRequest.getStringParam('symbol', 'CRM')
    17        );
    18        request.setMethod('GET');
    19       
    20        try {
    21            HTTPResponse response = http.send(request);
    22            JSONParser parser = JSON.createParser(response.getBody());
    23           
    24            List<Map<String, Object>> returnItems = new List<Map<String, Object>>();
    25            while (parser.nextToken() != null) {
    26                if (parser.getCurrentToken() == JSONToken.START_OBJECT && parser.getCurrentName() != null && parser.getCurrentName().startsWith('20')) {
    27                    String dateLabel = parser.getCurrentName();
    28                    parser.nextToken();
    29                    parser.nextToken();
    30                    System.debug(parser.getText());
    31                   
    32                    Map<String, Object> curRow = new Map<String, Object>();
    33                    curRow.put('date', dateLabel);
    34                    curRow.put('value', Double.valueOf(parser.getText()));
    35                    returnItems.add(curRow);
    36                }
    37            }
    38                               
    39            return JSON.serialize(new ApexStepResponse(returnItems));
    40        } catch(Exception exp) {
    41            System.debug('exception '+exp);
    42        }
    43
    44       
    45        return '';
    46    }
    47
    48}
  4. Add two more Apex classes for ApexStepRequest and ApexStepResponse to support the Apex stocks class.
    The code for these classes, along with the stock step code, can be found in this public AnalyticsApexSteps GitHub repo, in the /force-app/main/apex/common directory. This GitHub repo also contains other Apex step examples.
  5. Click Save.
    The StocksRestControl apex class appears.

Allow the External Website

To enable Apex to query external REST endpoints, allow the website in Salesforce.
  1. From setup, enter Remote in the Quick Find box, and select Remote Site Settings.
  2. Click New Remote Site.
    The page shows all sites that are allowed.
  3. Enter the remote site name and URL.
    The page shows the remote site name, URL, and description.
  4. Click Save.

Create the Apex Step

Manually define the apex step in the dashboard JSON to get the stock results from the Apex class that you previously created.
In the dashboard JSON, add the following apex step.
1"StockData": {
2    "query": {
3        "body": {
4            "symbol": "{{cell(CompaniesList_1.selection, 0, \"value\").asString()}}"
5        },
6        "path": "stocks"
7    },
8    "type": "apex"
9}
The apex step query contains the following parameters.
body
The binding retrieves the stock symbol when a company is selected in the toggle widget.The Salesforce option is selected in the toggle widget, which filters the table and chart widgets and displays the stock symbol in the text widget.
path
Specifies the REST API resource path to the Apex controller, as specified in the urlMapping of the RestResource annotation on the Apex controller.

The dashboard shows four widgets. The toggle widget is based on a static step that maps predefined company names to stock symbols. The table widget and line chart use the apex step to retrieve the results. The text widget uses a binding to concatenate “Selected symbol:” and the stock symbol of the selected company in the toggle widget.

Here’s the final dashboard JSON.
1{
2    "label": "Stock Quotes",
3    "mobileDisabled": false,
4    "state": {
5        "dataSourceLinks": [],
6        "filters": [],
7        "gridLayouts": [
8            {
9                "name": "Default",
10                "numColumns": 12,
11                "pages": [
12                    {
13                        "label": "Untitled",
14                        "name": "b177a6e6-8ab6-4914-af36-09c7fa23e0c8",
15                        "widgets": [
16                            {
17                                "colspan": 6,
18                                "column": 0,
19                                "name": "pillbox_1",
20                                "row": 0,
21                                "rowspan": 1,
22                                "widgetStyle": {
23                                    "borderEdges": []
24                                }
25                            },
26                            {
27                                "colspan": 5,
28                                "column": 7,
29                                "name": "text_1",
30                                "row": 0,
31                                "rowspan": 1,
32                                "widgetStyle": {
33                                    "borderEdges": []
34                                }
35                            },
36                            {
37                                "colspan": 6,
38                                "column": 0,
39                                "name": "table_1",
40                                "row": 1,
41                                "rowspan": 7,
42                                "widgetStyle": {
43                                    "borderEdges": []
44                                }
45                            },
46                            {
47                                "colspan": 6,
48                                "column": 6,
49                                "name": "chart_1",
50                                "row": 1,
51                                "rowspan": 7,
52                                "widgetStyle": {
53                                    "borderEdges": []
54                                }
55                            }
56                        ]
57                    }
58                ],
59                "rowHeight": "normal",
60                "selectors": [],
61                "style": {
62                    "alignmentX": "left",
63                    "alignmentY": "top",
64                    "backgroundColor": "#F2F6FA",
65                    "cellSpacingX": 8,
66                    "cellSpacingY": 8,
67                    "fit": "original",
68                    "gutterColor": "#C5D3E0"
69                },
70                "version": 1
71            }
72        ],
73        "layouts": [],
74        "steps": {
75            "CompaniesList_1": {
76                "datasets": [],
77                "dimensions": [],
78                "groups": [],
79                "label": "CompaniesList",
80                "numbers": [],
81                "selectMode": "singlerequired",
82                "strings": [],
83                "type": "staticflex",
84                "values": [
85                    {
86                        "display": "Salesforce",
87                        "value": "CRM"
88                    },
89                    {
90                        "display": "Apple",
91                        "value": "AAPL"
92                    },
93                    {
94                        "display": "Oracle",
95                        "value": "ORCL"
96                    },
97                    {
98                        "display": "Twitter",
99                        "value": "TWTR"
100                    },
101                    {
102                        "display": "Facebook",
103                        "value": "FB"
104                    }
105                ],
106                "broadcastFacet": true
107            },
108            "StockData": {
109                "query": {
110                    "body": {
111                        "symbol": "{{cell(CompaniesList_1.selection, 0, \"value\").asString()}}"
112                    },
113                    "path": "stocks"
114                },
115                "type": "apex"
116            }
117        },
118        "widgetStyle": {
119            "backgroundColor": "#FFFFFF",
120            "borderColor": "#E6ECF2",
121            "borderEdges": [],
122            "borderRadius": 0,
123            "borderWidth": 1
124        },
125        "widgets": {
126            "table_1": {
127                "parameters": {
128                    "borderColor": "#e0e5ee",
129                    "borderWidth": 1,
130                    "cell": {
131                        "backgroundColor": "#ffffff",
132                        "fontColor": "#16325c",
133                        "fontSize": 12
134                    },
135                    "columns": [],
136                    "customBulkActions": [],
137                    "exploreLink": false,
138                    "header": {
139                        "backgroundColor": "#f4f6f9",
140                        "fontColor": "#16325c",
141                        "fontSize": 12
142                    },
143                    "innerMajorBorderColor": "#a8b7c7",
144                    "innerMinorBorderColor": "#e0e5ee",
145                    "mode": "fittocontainer",
146                    "numberOfLines": 1,
147                    "step": "StockData",
148                    "verticalPadding": 8,
149                    "evenRowColor": null,
150                    "oddRowColor": null
151                },
152                "type": "table"
153            },
154            "pillbox_1": {
155                "parameters": {
156                    "compact": false,
157                    "exploreLink": false,
158                    "step": "CompaniesList_1"
159                },
160                "type": "pillbox"
161            },
162            "text_1": {
163                "parameters": {
164                    "fontSize": 20,
165                    "text": "Selected symbol: {{ cell(CompaniesList_1.selection, 0, \"value\").asString() }}",
166                    "textAlignment": "center",
167                    "textColor": "#091A3E"
168                },
169                "type": "text"
170            },
171            "chart_1": {
172                "parameters": {
173                    "autoFitMode": "keepLabels",
174                    "showPoints": false,
175                    "legend": {
176                        "showHeader": true,
177                        "show": true,
178                        "customSize": "auto",
179                        "position": "right-top",
180                        "inside": false
181                    },
182                    "axisMode": "multi",
183                    "tooltip": {
184                        "showBinLabel": true,
185                        "measures": "",
186                        "showPercentage": false,
187                        "showDimensions": true,
188                        "showMeasures": true,
189                        "customizeTooltip": false,
190                        "dimensions": ""
191                    },
192                    "visualizationType": "line",
193                    "dashLine": {
194                        "measures": "",
195                        "showDashLine": false
196                    },
197                    "exploreLink": false,
198                    "title": {
199                        "fontSize": 14,
200                        "subtitleFontSize": 11,
201                        "label": "",
202                        "align": "center",
203                        "subtitleLabel": ""
204                    },
205                    "trellis": {
206                        "flipLabels": false,
207                        "showGridLines": true,
208                        "size": [
209                            100,
210                            100
211                        ],
212                        "enable": false,
213                        "type": "x",
214                        "chartsPerLine": 4
215                    },
216                    "fillArea": true,
217                    "showZero": true,
218                    "measureAxis2": {
219                        "sqrtScale": false,
220                        "showTitle": true,
221                        "showAxis": true,
222                        "title": "",
223                        "customDomain": {
224                            "showDomain": false
225                        }
226                    },
227                    "measureAxis1": {
228                        "sqrtScale": false,
229                        "showTitle": true,
230                        "showAxis": true,
231                        "title": "",
232                        "customDomain": {
233                            "showDomain": false
234                        }
235                    },
236                    "theme": "wave",
237                    "step": "StockData",
238                    "dimensionAxis": {
239                        "showTitle": true,
240                        "customSize": "auto",
241                        "showAxis": true,
242                        "title": "",
243                        "icons": {
244                            "useIcons": false,
245                            "iconProps": {
246                                "fit": "cover",
247                                "column": "",
248                                "type": "round"
249                            }
250                        }
251                    },
252                    "drawArea": {
253                        "measure": "",
254                        "showDrawArea": false,
255                        "bounding1": "",
256                        "bounding2": ""
257                    }
258                },
259                "type": "chart"
260            }
261        }
262    },
263    "datasets": []
264}