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

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.

| improve this answer | |
  • So, in conclusion, VF + lightning:container, right? – Christian Szandor Knapp Jul 29 '18 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 Jul 29 '18 at 10:33
  • I agree for most Usecases. Valid in my eyes would be tooling API for example. – Christian Szandor Knapp Jul 29 '18 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 Jul 29 '18 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 Jul 29 '18 at 17:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.