Skip to content

Instantly share code, notes, and snippets.

@martyychang
Last active May 26, 2018 15:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save martyychang/6ef675e598838fa0013d to your computer and use it in GitHub Desktop.
Save martyychang/6ef675e598838fa0013d to your computer and use it in GitHub Desktop.
Demonstration of using Apex as a conduit for accessing the Salesforce1 Reporting REST API in Lightning
public class S1Reporting {
/*
* @see Salesforce1 Reporting REST API Developer Guide
*/
public class GetAnalyticsReportsResponseBody {
@AuraEnabled
public String name;
@AuraEnabled
public String id;
@AuraEnabled
public String url;
@AuraEnabled
public String describeUrl;
@AuraEnabled
public String instancesUrl;
}
}
public class S1ReportingClient {
public static final String OPERATION_PREFIX = '/services/data/v32.0';
public String accessToken;
public String hostname;
public HttpResponse lastHttpResponse;
public S1ReportingClient(String hostname, String accessToken) {
this.accessToken = accessToken;
this.hostname = hostname;
}
public Boolean getAnalyticsReports() {
HttpRequest request = new HttpRequest();
request.setMethod('GET');
request.setEndpoint(getHttpsEndpoint('/analytics/reports'));
request.setHeader('Authorization', 'Bearer ' + accessToken);
lastHttpResponse = new Http().send(request);
System.debug('lastHttpResponse.getBody(): ' + lastHttpResponse.getBody());
return lastHttpResponse.getStatusCode() == 200;
}
public List<S1Reporting.GetAnalyticsReportsResponseBody> getAnalyticsReportsResponse() {
return (List<S1Reporting.GetAnalyticsReportsResponseBody>)JSON.deserialize(
lastHttpResponse.getBody(), List<S1Reporting.GetAnalyticsReportsResponseBody>.class);
}
public String getHttpsEndpoint(String operation) {
return 'https://' + hostname + OPERATION_PREFIX + operation;
}
}
({
handleInit : function(component, event, helper) {
var self = this; // safe reference
var getAnalyticsReports =
component.get("c.getAnalyticsReports");
getAnalyticsReports.setCallback(self, function(a) {
console.log("returned: %o", a.getReturnValue());
component.set("v.reports", a.getReturnValue());
});
$A.enqueueAction(getAnalyticsReports);
}
})
<aura:application controller="ccmt.S1ReportingDemoController">
<aura:attribute name="reports" type="Object[]"/>
<aura:handler name="init" value="{!this}" action="{!c.handleInit}"/>
<h1>Salesforce1 Reporting REST API Demo</h1>
<aura:iteration items="{!v.reports}" var="report">
<h2>{!report.name}</h2>
<ul>
<li>name: {!report.name}</li>
<li>id: {!report.id}</li>
<li>url: {!report.url}</li>
<li>describeUrl: {!report.describeUrl}</li>
<li>instancesUrl: {!report.instancesUrl}</li>
</ul>
</aura:iteration>
</aura:application>
public class S1ReportingDemoController {
@AuraEnabled
public static List<S1Reporting.GetAnalyticsReportsResponseBody> getAnalyticsReports() {
// The server or hostname must be added as a remote site
// in Setup > Security Controls > Remote Site Settings
String server = 'ccmt-dev-ed.my.salesforce.com';
// Construct a new REST API client to connect to the
// specified server, using the current user's Session ID
// as the OAuth access token
S1ReportingClient client = new S1ReportingClient(
server, UserInfo.getSessionId());
// Attempt the desired operation, and return the
// parsed response if successful, or return null
// if unsuccessful
return client.getAnalyticsReports()
? client.getAnalyticsReportsResponse() : null;
}
}
@ozanbotan
Copy link

Hi,

I've tried to use structure above on my dev org. When page is rendered, i get "lastHttpResponse.getBody(): [{"message":"This session is not valid for use with the REST API","errorCode":"INVALID_SESSION_ID"}]" message as a debug log so that nothing is displayed in app.
I think getSessionId() method of UserInfo class does not work appropriately for @AuraEnabled methods. Because i suppose that there are two different session Id's are used by Salesforce and Aura Framework on ORG while async processing. Did you get an error message like that? Or have you ever heard sth related to my words?

@ZergyPoo
Copy link

Yes, I also get the [{"message":"This session is not valid for use with the REST API","errorCode":"INVALID_SESSION_ID"}] message.

I think the session Id generated from within the lightning context doesn't work.

If you were to run this apex method from somewhere else, like through anonymous apex, it works, I've done something similar. But when the lightning component calls it, the session Id is invalid.

@illarionovam
Copy link

Got exactly the same problem as @ozanbotan and @ZergyPoo
Has anyone found the dolution for this?

@markgarg
Copy link

From the docs, you need to use a Named Credential:
https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/apex_api_calls.htm#apex_api_calls

By security policy, sessions created by Lightning components aren’t enabled for API access. This prevents even your Apex code from making API calls to Salesforce. Using a named credential for specific API calls allows you to carefully and selectively bypass this security restriction.
The restrictions on API-enabled sessions aren’t accidental. Carefully review any code that uses a named credential to ensure you’re not creating a vulnerability.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment