Post on 28-Apr-2018
transcript
An Introduction to the Analytics API in Apex
Peter Knolle - peterknolle.com Salesforce.com Solutions Architect – Trifecta Technologies
What will be covered
� History / Background
� Example uses
� Running a report
� Accessing report metadata
� Filtering
� Unit testing
� Debugging / Exploring the API
History
� Salesforce had excellent reporting capabilities, but…
� …did not have an “official/supported” way to access the reports through code.
� Screen scraping – Ick!
� iframe – Yuck!
Analytics API Releases
� Winter ‘14 – REST-based API released � Requires Oauth session � JSON requests/ responses
� Spring ‘14 – Apex-based API released � Same functionality as REST-based API, but in Apex
What can we do with it?
� Easily use with charting libraries such as d3, Google Charts, etc.
What can we do with it?
� Dynamic filtering
What can we do with it?
� Reduce maintenance: no need to create parallel SOQL to get report data.
� Dynamic Dashboards
� It is very new, so much much more to come…
API
� REST and Apex APIs have same functionality � Run reports (synchronous and asynchronous) � Get report metadata � Get report result data � Dynamic filtering � Get list of recent asynchronous report runs
� Classes are in the Reports namespace, e.g., Reports.ReportManager, Reports.ReportMetadata, etc.
Running a Report
� Set of four overloaded methods for both synchronous and asynchronous
� Synchronously Reports.ReportResults res = Reports.ReportManager.runReport(reportId);
� Asynchronously Reports.ReportInstance instance = Reports.ReportManager.runAsyncReport(reportId);
// later…
Reports.ReportResults res = instance.getReportResults();
Overloaded runReport / runAsyncReport methods
� runReport(reportId) – Includes summary level information but will not include details (i.e., rows).
� runReport(reportId, includeDetails) – Includes the details, too.
� runReport(reportId, metadata) – Applies additional filters specified in the Reports.ReportMetadata metadata argument
� runReport(reportId, metadata, includeDetails) – Includes the details, too.
More on Asynchronous
Reports.ReportInstance instance = Reports.ReportManager.runAsyncReport(reportId);
instId = instance.getId();
//some other method…
Reports.ReportInstance inst = Reports.ReportManager.getInstance(instId);
String status = inst.getStatus();
if (status != 'Running’ && status != 'New’) {
reportResults = inst.getReportResults();
}
ReportResults
“Contains the results of running a report.”
� getFactMap() – Returns summary-level data or summary and detailed data for each row or column grouping. Detailed data is available if the includeDetails parameter is set to true when the report is run.
Fact Map Keys
Report format Fact map key pattern
Tabular T!T: The grand total of a report. Both record data values and the grand total are represented by this key.
Summary <First level row grouping_second level row grouping_third level row grouping>!T: T refers to the row grand total.
Matrix <First level row grouping_second level row grouping>!<First level column grouping_second level column grouping>.
Report with two grouping levels
Using ReportResults – Aggregates
Map<String,ReportFact> fm = results.getFactMap();
Reports.ReportFact fact = fm.get(‘T!T’);
Decimal grandTotal = (Decimal) fact.getAggregates().get(0).getValue();
Decimal rowCount = (Decimal) fact.getAggregates().get(1).getValue();
Using ReportResults - Details
Reports.ReportResults results = Reports.ReportManager.runReport(REPORT_ID, true);
Using ReportResults - Details
Reports.ReportFactWithDetails detailFact = (Reports.ReportFactWithDetails)results.getFactMap().get('0_0!T');
List<Reports.ReportDetailRow> allRows = detailFact.getRows();
Decimal cellValue = (Decimal) rows.get(0).getDataCells().get(0).getValue();
System.assert(cellValue == 114048);
Want more on the fact map?
� See Decode the Fact Map section in Apex Developer’s Guide:http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_analytics_fact_map.htm
Metadata
Three types of metadata
� Report Metadata � Reports.ReportMetadata
� Report Extended Metadata � Reports.ReportExtendedMedtadata
� Report Type Metadata � Reports.ReportTypeMetadata
ReportMetadata
“Report metadata gives information about the report as a whole, such as the report type, format, summary fields, row or column groupings, and filters that are saved to the report.“
� Simple attributes - getId(), getName(), getDeveloperName(), getReportFormat(), getReportType()
� Complex collections - getReportFilters(), getDetailColumns(), getAggregates(), getGroupingsDown/Across()
Accessing ReportMetadata
Reports.ReportDescribeResult descRes = Reports.ReportManager.describeReport(reportId);
ReportMetadata md = descRes.getReportMetadata(),
OR the ReportMetadata from a specific run
ReportMetadata md = reportResults.getReportMetadata();
// Example Uses
Id reportId = md.getId();
List<String> colApiNames = md.getDetailColumns();
ReportExtendedMetadata
“Report extended metadata provides additional, detailed metadata about summary and grouping fields, including data type and label information.”
� getAggregateColumnInfo() – API name, label, data type of aggregations (row count, sum, etc.)
� getDetailColumnInfo() – API name, label, data type of columns
� getGroupingColumnInfo() – API name, label, data type, grouping level of each grouping in the ReportMetadata’s groupingsDown/Across.
Accessing ReportExtendedMetadata
Reports.ReportDescribeResult descRes = Reports.ReportManager.describeReport(reportId);
Reports.ReportExtendedMetadata md = descRes.getReportExtendedMetadata(),
OR the ReportExtendedMetadata for a specific run
Reports.ReportExtendedMetadata emd = reportResults.getReportExtendedMetadata();
Accessing ReportExtendedMetadata
Integer level = emd.getGroupingColumnInfo()
.get(‘STAGE_NAME’)
.getGroupingLevel();
System.assert(0 == level);
ReportTypeMetadata
“Contains report type metadata, which gives you information about the fields that are available in each section of the report type, plus filter information for those fields.”
� List<Reports.ReportTypeColumnCategory> getCategories()– returns a list of categories, which in turn contain their list of fields with information about the fields
Accessing ReportTypeMetadata
Reports.ReportDescribeResult descRes = Reports.ReportManager.describeReport(reportId);
Reports.ReportTypeMetadata tmd = descRes.getReportTypeMetadata(),
// Not part of Reports.ReportResults
Accessing ReportTypeMetadata
Reports.ReportTypeColumnCategory category = tmd.getCategories().get(0);
String oppInfoLabel = category.getLabel();
Boolean isFilterable = category
.getColumns().get(‘AMOUNT’)
.getFilterable();
Filtering
� Columns must be filterable.
� Must use only allowed filter operators per data type – ReportManager. getDatatypeFilterOperatorMap()
� Can override existing filter by getting and setting value
� Can add additional filters
� Use Reports.ReportMetadata run/AsyncReport versions, e.g., � runReport(reportId, reportMetadata)
Adding a filter
Reports.ReportFilter fromFilter = new Reports.ReportFilter();
fromFilter.setColumn('CLOSE_DATE');
fromFilter.setOperator('greaterOrEqual');
fromFilter.setValue('2014-01-01');
Reports.ReportDescribeResult dr = Reports.ReportManager.describeReport(REPT_ID)
Reports.ReportMetadata md = dr.getReportMetadata();
md.getReportFilters().add(fromFilter);
Reports.ReportResults results = Reports.ReportManager.runReport(REPT_ID, md, true);
Unit Testing
� Report runs always ignore SeeAllData annotation, and always include org data
� Use a filter to limit testing to data created in the unit test
Opportunity opp = TestUtil.generateOpp(‘ApexUnitTest’);
List<Reports.ReportFilter> filters = getTestFilter(opp.Name);
reportMetadata.setReportFilters(filters);
Exploring / Debugging
� Useful to see entire object
� Helpful to determine API names
� Debug logs and Developer Console aren’t really designed for viewing that information
Debugging - JSON
Output to <pre> tag JSON.serailizePretty(results);
public String debugRes{ get; set; }
// somewhere in a method
Reports.ReportResults results = Reports.ReportManager.runReport(REPORT_ID);
debugRes = JSON.serializePretty(results);
<apex:outputPanel id="debug">
<pre>{!debugRes}</pre>
</apex:outputPanel>
Debugging View State
Debugging REST Explorer
Selected Limitations
� 500 synchronous report runs / hour
� 20 synchronous report run requests at a time
� 1,200 asynchronous requests / hour
� 200 requests at a time for async instances
� Returns up to the first 2,000 report rows
� Apex: Asynchronous not allowed in Batch
� Apex: Report runs in unit tests include org data
What was covered
� Apex API new in Spring ’14
� Some examples
� Methods to run reports, filter, get results, get metadata
� Unit testing
� Debugging / Exploring
More
� Apex Developer’s Guide - http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_analytics_intro.htm
� Articles by Product Manager, Analytics @ Salesforce: https://medium.com/@arun_sfdc
� Articles on my blog – http://peterknolle.com/posts
� Spring ‘14 right around the corner or get a pre-release org in the meantime