5

BACKGROUND

I would like to be able to interact with the various Salesforce REST API from client-side JavaScript code, without needing to go via a Apex controller method and then making a separate Apex callout.

I have created a POC component:

Component

<aura:component controller="JavaScriptForceController" implements="flexipage:availableForAllPageTypes">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <ltng:require scripts="{!$Resource.jsforce + '/jsforce.min.js'}" />
</aura:component>

JavaScript Controller

({
    doInit : function(cmp, event, helper) {

        helper.callAction(cmp, 'c.getSessionID', null, function(sessionId){
            console.log(sessionId) 

            let params = {};
            params.sessionId = sessionId;
            params.serverUrl = 'https://xxx-dev-ed.lightning.force.com';
            params.instanceUrl = 'https://xxx-dev-ed.lightning.force.com';
            params.logLevel = 'DEBUG';
            params.version = '43.0';

            var conn = new jsforce.Connection(params);
            conn.sobject("Account").describe(function(err, meta) {

                if (err) return console.error(err); 

                console.log('Label : ' + meta.label);
                console.log('Num of Fields : ' + meta.fields.length);

                meta.fields.forEach(function(field) {
                    console.log(field.name + ' - '  + field.label + ' - ' + field.type);
                });
            });
        });
    }
})

Apex Controller

public class JavaScriptForceController {

    @AuraEnabled
    public static String getSessionID(){

        return UserInfo.getSessionID();

    }
}

And a JavaScript Helper

({
    callAction : function(cmp, methodName, params, callback){
        var self = this;
        var action = cmp.get(methodName); 
        if (params != null) action.setParams(params);
        action.setCallback(this, function(response) {
            var state = response.getState();
            console.log(methodName + ' ' + state);
            if(cmp.isValid() && state === "SUCCESS"){
                var result = response.getReturnValue();
                console.log(result);
                if (callback) callback(result);
            } else if (state === "ERROR"){
                console.log(response.getError());
            }
        });

        $A.getCallback(function() {
            $A.enqueueAction(action); 
        })();  
    },
})

CSP Trusted Sites Definition

Add a rule: https://xxx-dev-ed.my.salesforce.com

Cross-origin resource sharing (CORS).

Add rules:

  1. https://xxx-dev-ed.lightning.force.com
  2. https://xxx-dev-ed.my.salesforce.com

QUESTIONS

  1. Why do I still get these errors (see below)?
  2. Is it even possible to even use JsForce in Lightning?
  3. If not, are there any other JavaScript librarys I could use to easily interact with the Salesforce REST APIs?

method=GET, url=/services/data/v43.0/sobjects/Account/describe GET https://xxx-dev-ed.my.salesforce.com/services/data/v43.0/sobjects/Account/describe 401 (Unauthorized)

JsForce_Test:1 Failed to load https://xxx-dev-ed.my.salesforce.com/services/data/v43.0/sobjects/Account/describe: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://xxx-dev-ed.lightning.force.com' is therefore not allowed access.

The response had HTTP status code 401.

jsforce.min.js:3 elappsed time : 168msec jsforce.min.js:3 status=400, url=/services/data/v43.0/sobjects/Account/describe

Cross-Origin Read Blocking (CORB) blocked cross-origin response https://xxx-dev-ed.my.salesforce.com/services/data/v43.0/sobjects/Account/describe with MIME type application/json.

JavaScriptForce.js:24 Error: Access Declined

Reference

4
  • Try using a container component to make the call... This could prevent the cross origin issues you are facing. Commented Jul 29, 2018 at 8:14
  • @CasparHarmer Thanks for responding. What do you mean by 'Container Component'?
    – Robs
    Commented Jul 29, 2018 at 8:15
  • Great question. I believe Caspar means a lightning:container in which a VF page could live doing the call outs and communicating stuff back to LEX cmps via window.message => developer.salesforce.com/docs/atlas.en-us.lightning.meta/… Commented Jul 29, 2018 at 10:07
  • Also check the server/instance urls. You put 'lightning' in and I believe it should point to the classic URL like xxx-dev-ed.my.salesforce.com Commented Jul 29, 2018 at 10:20

1 Answer 1

8

Why do I still get these errors (see below)?

You've got two things working against you: CORB and Lightning Session Id. First, CORB is a new security feature that prevents certain types of resources from being returned to the client. As far as I can tell, you can't circumvent this at all. Second, the Lightning Session Id does not have API access, so you'd have to hit the server at least once to get a compatible Session ID anyways. Overall, whatever you're attempting to do will not work well in Lightning. You should be able to do this in Visualforce, because it has an API-capable session Id and doesn't have to go across domains. The original error would have been INVALID_SESSION_ID (so you got a 401), but it was filtered out by CORB, so all your script sees is the secondary error.

Is it even possible to even use JsForce in Lightning?

Absolutely not. CORB will block all responses, because there's no API endpoint mapped to lightning.force.com. This is a browser-based security feature.

If not, are there any other JavaScript librarys I could use to easily interact with the Salesforce REST APIs?

Because of all the security restrictions, you simply won't be able to do this. There was a "hack" you could do in the past (grabbing a Visualforce Session Id), but it won't work any longer. You will necessarily need Visualforce if you want any sort of API access.

9
  • So, in conclusion, VF + lightning:container, right? Commented Jul 29, 2018 at 10:28
  • 2
    @ChristianSzandorKnapp I think so, as long as the VF page makes the calls; you'd basically be using the Visualforce page as a proxy server to Salesforce. I can't see how this would be the lesser of two evils as opposed to just using Apex Code directly.
    – sfdcfox
    Commented Jul 29, 2018 at 10:33
  • I agree for most Usecases. Valid in my eyes would be tooling API for example. Commented Jul 29, 2018 at 10:47
  • @sfdcfox Thank you. Do we know if there is any plan by Salesforce to a Lightning JavaScript library which has the same capability, or is it impossible due to the security restrictions?
    – Robs
    Commented Jul 29, 2018 at 11:09
  • 1
    @Robs CORB + Lightning essentially means that all callouts to APIs will need to be Apex-based to succeed. I suspect CORB broke a lot of integrations and apps in Salesforce.
    – sfdcfox
    Commented Jul 29, 2018 at 17:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .