Skip to content
This repository

ForceTK - a minimal Force.com REST API for JavaScript apps

branch: master
Octocat-spinner-32 .gitignore Added tests for RemoteTKController.cls March 21, 2013
Octocat-spinner-32 README.markdown Added upsert March 12, 2013
Octocat-spinner-32 RemoteTK.component Added upsert March 12, 2013
Octocat-spinner-32 RemoteTKController.cls Accept String or correctly typed arguments in create, update, upsert.… April 16, 2013
Octocat-spinner-32 RemoteTKExample.page Added RemoteTK October 01, 2012
Octocat-spinner-32 RemoteTKMobile.page Added mobile version of RemoteTK demo October 15, 2012
Octocat-spinner-32 TestRemoteTKController.cls Accept String or correctly typed arguments in create, update, upsert.… April 16, 2013
Octocat-spinner-32 ajax.gif Updated forcetk.js to work with proxy, added proxy, refactored sample… April 15, 2011
Octocat-spinner-32 app.js Added error handling to sample JS app. Closes #1 June 29, 2011
Octocat-spinner-32 example.html Added pointers to jQuery, jQuery-swip etc May 31, 2011
Octocat-spinner-32 example.page Added persistent storage of refresh token to the PhoneGap sample app,… May 24, 2011
Octocat-spinner-32 forcetk.js dont send contentType for DELETE and update version to v27 April 29, 2013
Octocat-spinner-32 license Added toolkit, readme, example March 29, 2011
Octocat-spinner-32 mobile.html Added pointers to jQuery, jQuery-swip etc May 31, 2011
Octocat-spinner-32 mobile.page Added persistent storage of refresh token to the PhoneGap sample app,… May 24, 2011
Octocat-spinner-32 mobileapp.js Added PhoneGap app May 03, 2011
Octocat-spinner-32 oauthcallback.html Updated forcetk.js to work with proxy, added proxy, refactored sample… April 15, 2011
Octocat-spinner-32 phonegap.html Added clarification on file location May 31, 2011
Octocat-spinner-32 proxy.php Merge pull request #23 from cwarden/cloudforce-support March 12, 2013
Octocat-spinner-32 style.css Updated forcetk.js to work with proxy, added proxy, refactored sample… April 15, 2011
README.markdown

Force.com JavaScript REST Toolkit

This minimal toolkit allows JavaScript in web pages to call the Force.com REST API in a number of different ways.

Background

Due to the same origin policy, JavaScript running in Visualforce pages may not use XmlHttpRequest to directly invoke the REST API, since Visualforce pages have hostnames of the form abc.na1.visual.force.com, and the REST API endpoints are of the form na1.salesforce.com.

The RemoteTK Visualforce Custom Component (comprising RemoteTK.component and RemoteTKController.cls) provides an abstraction very similar to the REST API, implemented via @RemoteAction methods in the component's controller. The advantage of this mechanism is that no API calls are consumed.

Alternatively, the ForceTK JavaScript library works around the same origin restriction by using the AJAX Proxy to give full access to the REST API. Since the AJAX proxy is present on all Visualforce hosts with an endpoint of the form https://abc.na1.visual.force.com/services/proxy, our Visualforce-hosted JavaScript can invoke it, passing the desired resource URL in an HTTP header. A drawback here is that using the REST API, even from a Visualforce page, consumes API calls.

To host JavaScript outside the Force.com platform, we can deploy a simple PHP proxy to perform the same function as the AJAX proxy.

PhoneGap provides a way for HTML5/JavaScript apps to run as native applications; in this configuration a proxy is not required - the toolkit simply provides a convenient abstraction of the REST API.

Dependencies

The toolkit uses jQuery. It has been tested on jQuery 1.4.4 and 1.5.2, but other versions may also work.

Configuration

RemoteTK requires no configuration.

ForceTK requires that you add the correct REST endpoint hostname for your instance (i.e. https://na1.salesforce.com/ or similar) as a remote site in Your Name > Administration Setup > Security Controls > Remote Site Settings.

Using RemoteTK in a Visualforce page

Add RemoteTKController.cls and RemoteTK.component to your org by creating an Apex Class and a Component and pasting in the respective content, pasting the files into a Force.com IDE project, or by using the Force.com Migration Tool.

Your Visualforce page will need to include the component and create a client object. An absolutely minimal sample is:

<apex:page>
    <!-- Include the RemoteTK component -->
    <c:RemoteTK />
    <apex:includeScript value="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js" />
    <script type="text/javascript">
        // Get a reference to jQuery that we can work with
        $j = jQuery.noConflict();

        // Get an instance of the RemoteTK client
        var client = new remotetk.Client();

        client.query("SELECT Name FROM Account LIMIT 1", function(response){
            $j('#accountname').html(response.records[0].Name);
        });
    </script>
    <p>The first account I see is <span id="accountname"></span>.</p>
</apex:page>

More fully featured samples are provided in RemoteTKExample.page and RemoteTKMobile.page.

Using ForceTK in a Visualforce page

Create a zip file containing app.js, forcetk.js, jquery.js, and any other static resources your project may need. Upload the zip via Your Name > App Setup > Develop > Static Resources.

Your Visualforce page will need to include jQuery and the toolkit, then create a client object, passing a session ID to the constructor. An absolutely minimal sample is:

<apex:page>
    <apex:includeScript value="{!URLFOR($Resource.static, 'jquery.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.static, 'forcetk.js')}"  />
    <script type="text/javascript">
        // Get a reference to jQuery that we can work with
        $j = jQuery.noConflict();

        // Get an instance of the REST API client and set the session ID
        var client = new forcetk.Client();
        client.setSessionToken('{!$Api.Session_ID}');

        client.query("SELECT Name FROM Account LIMIT 1", function(response){
            $j('#accountname').html(response.records[0].Name);
        });
    </script>
    <p>The first account I see is <span id="accountname"></span>.</p>
</apex:page>

More fully featured samples are provided in example.page and mobile.page. Watch a brief demo of the samples.

Using the Toolkit in an HTML page outside the Force.com platform

You will need to deploy proxy.php to your server, configuring CORS support (see comments in proxy.php) if your JavaScript is to be hosted on a different server.

Your HTML page will need to include jQuery and the toolkit, then create a client object, passing a session ID to the constructor. An absolutely minimal sample using OAuth to obtain a session ID is:

<html>
  <head>

    <!-- 
    jQuery - http://docs.jquery.com/Downloading_jQuery
    -->
    <script type="text/javascript" src="static/jquery.js"></script>
    <!--
    From jQuery-swip - http://code.google.com/p/jquery-swip/source/browse/trunk/jquery.popupWindow.js 
    -->
    <script type="text/javascript" src="static/jquery.popup.js"></script>
    <script type="text/javascript" src="forcetk.js"></script>
    <script type="text/javascript">
        // OAuth Configuration
        var loginUrl    = 'https://login.salesforce.com/';
        var clientId    = 'YOUR_CLIENT_ID';
        var redirectUri = 'PATH_TO_YOUR_APP/oauthcallback.html';
        var proxyUrl    = 'PATH_TO_YOUR_APP/proxy.php?mode=native';

        var client = new forcetk.Client(clientId, loginUrl, proxyUrl);

        $(document).ready(function() {
            $('#message').popupWindow({ 
                windowURL: getAuthorizeUrl(loginUrl, clientId, redirectUri),
                windowName: 'Connect',
                centerBrowser: 1,
                height:524, 
                width:675
            });
        });

        function getAuthorizeUrl(loginUrl, clientId, redirectUri){
            return loginUrl+'services/oauth2/authorize?display=popup'
                +'&response_type=token&client_id='+escape(clientId)
                +'&redirect_uri='+escape(redirectUri);
        }

        function sessionCallback(oauthResponse) {
            if (typeof oauthResponse === 'undefined'
                || typeof oauthResponse['access_token'] === 'undefined') {
                $('#message').html('Error - unauthorized!');
            } else {
                client.setSessionToken(oauthResponse.access_token, null,
                    oauthResponse.instance_url);

                    client.query("SELECT Name FROM Account LIMIT 1", 
                      function(response){
                        $('#message').html('The first account I see is '
                          +response.records[0].Name);
                    });
            }
        }
    </script>
    <p id="message">Click here.</p>
</html>

More fully featured samples are provided in example.html and mobile.html.

Using the Toolkit in a PhoneGap app

Your HTML page will need to include jQuery, the toolkit, PhoneGap and the ChildBrowser plugin, then create a client object, passing a session ID to the constructor. You can use https://login.salesforce.com/services/oauth2/success as the redirect URI and catch the page load in ChildBrowser.

An absolutely minimal sample using OAuth to obtain a session ID is:

<html>
  <head>
    <script type="text/javascript" src="static/jquery.js"></script>
    <script type="text/javascript" src="forcetk.js"></script>
    <script type="text/javascript" src="phonegap.0.9.5.min.js"></script>
    <script type="text/javascript" src="ChildBrowser.js"></script>              
    <script type="text/javascript">
        // OAuth Configuration
        var loginUrl    = 'https://login.salesforce.com/';
        var clientId    = 'YOUR_CLIENT_ID';
        var redirectUri = 'https://login.salesforce.com/services/oauth2/success';

        var client = new forcetk.Client(clientId, loginUrl);

        $(document).ready(function() {
            var cb = ChildBrowser.install();
            $('#login').click(function(e) {
                e.preventDefault();
                cb.onLocationChange = function(loc){   
                    if (loc.startsWith(redirectUri)) {
                        cb.close();
                        sessionCallback(unescape(loc));
                    }
                };
                cb.showWebPage(getAuthorizeUrl(loginUrl, clientId, redirectUri));
            });
        });

        function getAuthorizeUrl(loginUrl, clientId, redirectUri){
            return loginUrl+'services/oauth2/authorize?display=touch'
                +'&response_type=token&client_id='+escape(clientId)
                +'&redirect_uri='+escape(redirectUri);
        }

        function sessionCallback(loc) {
            var oauthResponse = {};

            var fragment = loc.split("#")[1];

            if (fragment) {
                var nvps = fragment.split('&');
                for (var nvp in nvps) {
                    var parts = nvps[nvp].split('=');
                    oauthResponse[parts[0]] = unescape(parts[1]);
                }
            }

            if (typeof oauthResponse === 'undefined'
                || typeof oauthResponse['access_token'] === 'undefined') {
                errorCallback({
                              status: 0, 
                              statusText: 'Unauthorized', 
                              responseText: 'No OAuth response'
                              });
            } else {
                client.setSessionToken(oauthResponse.access_token, null,
                    oauthResponse.instance_url);

                client.query("SELECT Name FROM Account LIMIT 1", 
                    function(response){
                        $('#message').html('The first account I see is '
                        +response.records[0].Name);
                    }
                );
            }
        }
    </script>
    <p id="message">Click here.</p>
</html>

A fully featured sample (including persistence of the OAuth refresh token to the iOS Keychain) is provided in phonegap.html.

Something went wrong with that request. Please try again.