Oh my god. It's full of code!

Ask Kenji: Cross domain ajax requests?

I was just killing some time, chilling out after karate, and this message popped in my inbox.

Hi Kenji,

I have read some articles about Salesforce in your bolg. So I have a question want to ask you, I think maybe you can give me some advices.

I want to ues jquery.ajax method to invoke the apex class.
These jquery codes are written in a HTML page not a visualforce page. I have some method to get the access_token based on the OAuth 2.0.
Then I follow your article (https://iwritecrappycode.wordpress.com/2011/07/08/salesforce-rest-api-musings/) create a apex to listen my request. I use curl to test this class and successful.
So, I think I can use jquery.ajax do the same thing.

I post the same question on force.com boards, you can see the detail at there.(http://boards.developerforce.com/t5/Apex-Code-Development/Ues-jquery-ajax-to-invoke-apex-class/td-p/394713)

Do you have experience on this?

Thank you!

A valid question. I feel like I might have touched on it before, but hey no harm in writing about it again. It’s a common situation, and one with probably more than one solution. Below is my approach. Take it or leave it.

First off, as far as I know you can’t invoke a rest resource with pure javascript. The cross domain security issue just doesn’t allow for it. The only way to do cross domain ajax stuff is by tricking the browser to loading the remote resource as if it was a script resource, since those can be loaded from anywhere. This technique in jQuery is called jsonP. The problem with this is that you cannot set headers, include authorizations, or anything else that you do with a more complex http request. It’s a simple GET to the url, and that’s is. REST resources typically require an authorization header to be set, and need to support POST, PATCH, PUT, along with just GET. So most REST resources, including the ones you can make in Salesforce can’t be access directly via javascript. If someone can prove me wrong, I love you.

So what are we do to? The method that follows is what I’ve been doing when I need a pure javascript solution. It’s not the most elegant, but it works. Here is what you have to do (this method will also get around having to use REST services, or oAuth). First, setup an visualforce page with your apex class as the controller. Wrap the return data in the callback function provided via the jQuery get request, and print the results out. Host the visualforce page on a publicly accessible salseforce site (don’t forget to set permissions on the page and class to allow the public profile user to get access) jQuery will get the response, pass the data to the inline handler function and you can process the results as you need.

<apex:page showHeader="false" sidebar="false" standardStylesheets="false" contentType="application/x-JavaScript; charset=utf-8" controller="jsonp_controller">{!returnFunction}</apex:page>

Your controller will look something like this

public class jsonp_controller
{
    public string returnFunction{get;set;}
    
    public pageReference getReturnFunction()
    {
        //get the parameters from the get/post request and stash em in a map
        map<string,string> params  = ApexPages.currentPage().getParameters();
        
        //set your data to return here
        string returnData = 'blah';
        
        if(params.containsKey('callback'))
        {
            returnFunction = params.get('callback') + '(' + returnData + ');';
        }
        
        return null;
    }
    
    @isTest
    public static void test_jsonp_controller()
    {
        jsonp_controller controller = new jsonp_controller();
        system.assertEquals(controller.returnFunction,'blah');
        
        
    }
}

And finally your page that actually makes the request would look like this

<html>
<head>
    <title>Cross domain ajax to request to salesforce</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
    <script>
    var url = "http://yourSite.force.com/jsonp_getData";

    function loadData()
    {
        jQuery.getJSON(url+'?callback=?',function(data)
        {
            jQuery('#results').html(data);
        });

    }

    $(document).ready(function() {
        loadData()
    });
    
    </script>
</head>
    <body>
    <div id="results">
    Your remotly fetched data will get loaded here
        </div>
    </body>
</html>

Remember, your visualforce page that serves the content must be publicly available, that means hosting it on a force.com site. Please note I wasn’t able to actually test the above code, because my org is freaking out on me right now (seriously, it’s doing some weird stuff), but it should be pretty close to accurate. Anyway, I hope this helps some people out there.

PS: I knew this topic seemed familiar. It’s because i wrote about it before!
Salesforce SOQL Query to JSON

One response

  1. JIE

    Hi Kenji,

    Thanks for you article!
    Give me many help!

    Thank you!

    February 8, 2012 at 8:17 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s