Skip to content
This repository has been archived by the owner on Jan 10, 2024. It is now read-only.

V2 #88

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

V2 #88

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.DS_Store
.idea
2 changes: 1 addition & 1 deletion BulkAPISampleFiles/update.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<!-- Contact records -->
<sObjects xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<sObject>
<Id>003E000001CbzBi</Id>
<Id>003E000001VB8F6IAL</Id>
<Title>Pirate</Title>
</sObject>
</sObjects>
48 changes: 31 additions & 17 deletions BulkTK.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ Create a job
contentType : 'CSV'
};

client.createJob(job, function(response) {
client.createJob(job)
.then(function(response) {
jobId = response.jobInfo.id;
console.log('Job created with id '+jobId+'\n');
}, function(jqXHR, textStatus, errorThrown) {
})
.catch(function(jqXHR, textStatus, errorThrown) {
console.log('Error creating job', jqXHR.responseText);
});

Expand All @@ -69,10 +71,11 @@ You can add multiple batches to the job; each batch can contain up to 10,000 rec
"Tom,Jones,Marketing,1940-06-07Z,"Self-described as ""the top"" branding guru on the West Coast\n"+
"Ian,Dury,R&D,,"World-renowned expert in fuzzy logic design. Influential in technology purchases."\n";

client.addBatch(jobId, "text/csv; charset=UTF-8", csvData,
function(response){
client.addBatch(jobId, "text/csv; charset=UTF-8", csvData)
.then(function(response){
console.log('Added batch '+response.batchInfo.id+'. State: '+response.batchInfo.state+'\n');
}, function(jqXHR, textStatus, errorThrown) {
})
.catch(function(jqXHR, textStatus, errorThrown) {
console.log('Error adding batch', jqXHR.responseText);
});

Expand All @@ -83,18 +86,22 @@ Close the job

You must close the job to inform Salesforce that no more batches will be submitted for the job.

client.closeJob(jobId, function(response){
client.closeJob(jobId)
.then(function(response){
console.log('Job closed. State: '+response.jobInfo.state+'\n');
}, function(jqXHR, textStatus, errorThrown) {
})
.catch(function(jqXHR, textStatus, errorThrown) {
console.log('Error closing job', jqXHR.responseText);
});

Check batch status
------------------

client.getBatchDetails(jobId, batchId, function(response){
client.getBatchDetails(jobId, batchId)
.then(function(response){
console.log('Batch state: '+response.batchInfo.state+'\n');
}, function(jqXHR, textStatus, errorThrown) {
})
.catch(function(jqXHR, textStatus, errorThrown) {
console.log('Error getting batch details', jqXHR.responseText);
});

Expand All @@ -103,9 +110,10 @@ Get batch results

Pass `true` as the `parseXML` parameter to get batch results for a query, false otherwise.

client.getBatchResult(jobId, batchId, false, function(response){
client.getBatchResult(jobId, batchId, false)
.then(function(response){
console.log('Batch result: '+response);
}, function(jqXHR, textStatus, errorThrown) {
}).then(function(jqXHR, textStatus, errorThrown) {
console.log('Error getting batch result', jqXHR.responseText);
});

Expand All @@ -116,22 +124,28 @@ When adding a batch to a bulk query job, the `contentType` for the request must

var soql = 'SELECT Id, FirstName, LastName, Email FROM Contact';

client.addBatch(jobId, 'text/csv', soql, function(response){
client.addBatch(jobId, 'text/csv', soql)
.then(function(response){
console.log('Batch state: '+response.batchInfo.state+'\n');
}, function(jqXHR, textStatus, errorThrown) {
})
.catch(function(jqXHR, textStatus, errorThrown) {
console.log('Error getting batch result', jqXHR.responseText);
});

Getting bulk query results is a two step process. Call `getBatchResult()` with `parseXML` set to `true` to get a set of result IDs, then call `getBulkQueryResult()` to get the actual records for each result

client.getBatchResult(jobId, batchId, true, function(response){
client.getBatchResult(jobId, batchId, true)
.then(function(response){
response['result-list'].result.forEach(function(resultId){
client.getBulkQueryResult(jobId, batchId, resultId, function(response){
client.getBulkQueryResult(jobId, batchId, resultId)
.then(function(response){
console.log('Batch result: '+response);
}, function(jqXHR, textStatus, errorThrown) {
})
.catch(function(jqXHR, textStatus, errorThrown) {
console.log('Error getting bulk query results', jqXHR.responseText);
});
});
}, function(jqXHR, textStatus, errorThrown) {
})
.catch(function(jqXHR, textStatus, errorThrown) {
console.log('Error getting batch result', jqXHR.responseText);
});
43 changes: 43 additions & 0 deletions OlderUpdates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
Older Updates
=============

* [Visualforce Remote Objects](https://www.salesforce.com/us/developer/docs/pages/index_Left.htm#CSHID=pages_remote_objects.htm|StartTopic=Content%2Fpages_remote_objects.htm|SkinName=webhelp) are proxy objects that enable basic DML operations on sObjects directly from JavaScript. Behind the scenes, the Remote Objects controller handles sharing rules, field level security, and other data accessibility concerns. Pages that use Remote Objects are subject to all the standard Visualforce limits, but like JavaScript remoting, Remote Objects calls don’t count toward API request limits.


Since Remote Objects are more secure than RemoteTK (which does not respect sharing rules, FLS etc since system-level access is proxied via the RemoteTK controller), and similarly do not consume API calls (the main motivation for RemoteTK), RemoteTK has been removed from the toolkit.

* Since the Summer '13 release, the `/services/data` endpoint has been exposed on Visualforce hosts, so no proxy is now required for REST API calls in JavaScript served via Visualforce (although the proxy **is** still required for calls to `/services/apexrest`). `forcetk.js` has been updated to reflect this.

* Inserting or updating blob data using the `create` or `update` functions (passing base64-encoded binary data in JSON) is limited by the REST API to 50 MB of text data or 37.5 MB of base64–encoded data. New functions, `createBlob` and `updateBlob`, allow creation and update of ContentVersion and Document records with binary ('blob') content with a size of up to 500 MB. Here is a minimal sample that shows how to upload a file to Chatter Files:

<apex:page docType="html-5.0" title="File Uploader">
<h3>
Select a file to upload as a new Chatter File.
</h3>
<input type="file" id="file" onchange="upload()"/>
<p id="message"></p>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="{!$Resource.forcetk}"></script>
<script>
var client = new forcetk.Client();

client.setSessionToken('{!$Api.Session_ID}');

function upload() {
var file = $("#file")[0].files[0];
client.createBlob('ContentVersion', {
Origin: 'H', // 'H' for Chatter File, 'C' for Content Document
PathOnClient: file.name
}, file.name, 'VersionData', file)
.then(function(response){
console.log(response);
$("#message").html("Chatter File created: <a target=\"_blank\" href=\"/" + response.id + "\">Take a look!</a>");
})
.catch(function(request, status, response){
$("#message").html("Error: " + status);
});
}
</script>
</apex:page>

Under the covers, `createBlob` sends a multipart message. See the REST API doc page [Insert or Update Blob Data](https://www.salesforce.com/us/developer/docs/api_rest/Content/dome_sobject_insert_update_blob.htm) for more details.
79 changes: 26 additions & 53 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -13,73 +13,42 @@ Due to the [same origin policy](http://en.wikipedia.org/wiki/Same_origin_policy)
Recent Updates
--------------

* [Visualforce Remote Objects](https://www.salesforce.com/us/developer/docs/pages/index_Left.htm#CSHID=pages_remote_objects.htm|StartTopic=Content%2Fpages_remote_objects.htm|SkinName=webhelp) are proxy objects that enable basic DML operations on sObjects directly from JavaScript. Behind the scenes, the Remote Objects controller handles sharing rules, field level security, and other data accessibility concerns. Pages that use Remote Objects are subject to all the standard Visualforce limits, but like JavaScript remoting, Remote Objects calls don’t count toward API request limits.


Since Remote Objects are more secure than RemoteTK (which does not respect sharing rules, FLS etc since system-level access is proxied via the RemoteTK controller), and similarly do not consume API calls (the main motivation for RemoteTK), RemoteTK has been removed from the toolkit.

* Since the Summer '13 release, the `/services/data` endpoint has been exposed on Visualforce hosts, so no proxy is now required for REST API calls in JavaScript served via Visualforce (although the proxy **is** still required for calls to `/services/apexrest`). `forcetk.js` has been updated to reflect this.

* Inserting or updating blob data using the `create` or `update` functions (passing base64-encoded binary data in JSON) is limited by the REST API to 50 MB of text data or 37.5 MB of base64–encoded data. New functions, `createBlob` and `updateBlob`, allow creation and update of ContentVersion and Document records with binary ('blob') content with a size of up to 500 MB. Here is a minimal sample that shows how to upload a file to Chatter Files:

<apex:page docType="html-5.0" title="File Uploader">
<h3>
Select a file to upload as a new Chatter File.
</h3>
<input type="file" id="file" onchange="upload()"/>
<p id="message"></p>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="{!$Resource.forcetk}"></script>
<script>
var client = new forcetk.Client();

client.setSessionToken('{!$Api.Session_ID}');

function upload() {
var file = $("#file")[0].files[0];
client.createBlob('ContentVersion', {
Origin: 'H', // 'H' for Chatter File, 'C' for Content Document
PathOnClient: file.name
}, file.name, 'VersionData', file, function(response){
console.log(response);
$("#message").html("Chatter File created: <a target=\"_blank\" href=\"/" + response.id + "\">Take a look!</a>");
}, function(request, status, response){
$("#message").html("Error: " + status);
});
}
</script>
</apex:page>

Under the covers, `createBlob` sends a multipart message. See the REST API doc page [Insert or Update Blob Data](https://www.salesforce.com/us/developer/docs/api_rest/Content/dome_sobject_insert_update_blob.htm) for more details.
[Older Updates](OlderUpdates.md)

Dependencies
------------

The toolkit uses [jQuery](http://jquery.com/). It has been tested on jQuery 1.4.4 and 1.5.2, but other versions may also work.
The toolkit uses [ECMAScript 6 Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).

TBD - Babel

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*.
If you are using ForceTK from JavaScript hosted in an 'off platform' web page (for example, in a Heroku app), you will need to add the app's origin (protocol, host and port, for example https://myapp.herokuapp.com/) to your org's [CORS configuration](https://help.salesforce.com/htviewhelpdoc?err=1&id=extend_code_cors.htm&siteLang=en_US).

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*.
Create a zip file containing app.js, forcetk.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')}" />
<apex:includeScript value="{!$Resource.forcetk}" />
<script type="text/javascript">
// 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){
$('#accountname').text(response.records[0].Name);
});
// 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")
.then(function(response){
document.getElementById("accountname").textContent = response.records[0].Name;
})
.catch(function(error){
console.error(error);
alert(error);
});
</script>
<p>The first account I see is <span id="accountname"></span>.</p>
</apex:page>
Expand All @@ -89,9 +58,9 @@ More fully featured samples are provided in [example.page](Force.com-JavaScript-
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.
As mentioned above, you will need to [configure CORS](https://help.salesforce.com/htviewhelpdoc?err=1&id=extend_code_cors.htm&siteLang=en_US) to call the Force.com REST API from JavaScript hosted 'off-platform'.

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:
Your HTML page will need to include 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>
Expand Down Expand Up @@ -148,13 +117,17 @@ Your HTML page will need to include jQuery and the toolkit, then create a client
</script>
<p id="message">Click here.</p>
</html>

TBD - new OAuth!

More fully featured samples are provided in [example.html](Force.com-JavaScript-REST-Toolkit/blob/master/example.html) and [mobile.html](Force.com-JavaScript-REST-Toolkit/blob/master/mobile.html).

Using the Toolkit in a Cordova app
----------------------------------

Your HTML page will need to include jQuery, the toolkit and Cordova. You will also need to install the [InAppBrowser](http://plugins.cordova.io/#/package/org.apache.cordova.inappbrowser) plugin to be able to pop up a browser window for authentication. 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 InAppBrowser.
TBD - update for current Cordova!

Your HTML page will need to include the toolkit and Cordova. You will also need to install the [InAppBrowser](http://plugins.cordova.io/#/package/org.apache.cordova.inappbrowser) plugin to be able to pop up a browser window for authentication. 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 InAppBrowser.

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

Expand Down
33 changes: 23 additions & 10 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,16 @@
"WHERE "+$("#field").val()+" LIKE '%"+request.term+"%' "+
"ORDER BY Name LIMIT 20";

client.query(query, function( data ) {
client.query(query)
.then(function( data ) {
response( $.map( data.records, function( record ) {
return {
label: record.Name,
value: record.Id
}
}));
}, errorCallback);
})
.catch(errorCallback);
},
minLength: 2,
delay: 1000,
Expand Down Expand Up @@ -115,7 +117,9 @@

$('#list').html(ajaxgif+" creating account...");

client.create('Account', fields, createCallback, errorCallback);
client.create('Account', fields)
.then(createCallback)
.catch(errorCallback);
});
$dialog.dialog('option', 'title', 'New Account');
$dialog.dialog('open');
Expand Down Expand Up @@ -156,7 +160,7 @@
&& !response.Website.startsWith('http://')) {
response.Website = 'http://'+response.Website;
}
$dialog.TrimPath.processDOMTemplate("detail_jst"
$dialog.html(TrimPath.processDOMTemplate("detail_jst"
,response));
$dialog.find('#industry').click(function(e) {
e.preventDefault();
Expand All @@ -167,7 +171,9 @@
e.preventDefault();
$dialog.dialog('close');
$('#list').html(ajaxgif+" deleting account...");
client.del('Account', $dialog.find('#id').val(), deleteCallback, errorCallback);
client.del('Account', $dialog.find('#id').val())
.then(deleteCallback)
.catch(errorCallback);
});
$dialog.find('#edit').click(function(e) {
e.preventDefault();
Expand All @@ -187,7 +193,9 @@

$('#list').html(ajaxgif+" updating account...");

client.update('Account', $dialog.find('#id').val(), fields, updateCallback, errorCallback);
client.update('Account', $dialog.find('#id').val(), fields)
.then(updateCallback)
.catch(errorCallback);
});
});
}
Expand Down Expand Up @@ -217,8 +225,9 @@
$dialog.html(ajaxgif+" retrieving...");

// Get account details and populate the dialog
client.retrieve('Account', id, 'Name,Industry,TickerSymbol,Website'
, detailCallback, errorCallback);
client.retrieve('Account', id, 'Name,Industry,TickerSymbol,Website')
.then(detailCallback)
.catch(errorCallback);
}

function filterIndustry(industry) {
Expand All @@ -227,7 +236,9 @@
var query = "SELECT Id, Name FROM Account WHERE Industry = '"+industry
+"' ORDER BY Name LIMIT 20";

client.query(query, queryCallback, errorCallback);
client.query(query)
.then(queryCallback)
.catch(errorCallback);
}

function filterAccounts(field, value) {
Expand All @@ -238,6 +249,8 @@
+"%' ORDER BY Name LIMIT 20"
: "SELECT Id, Name FROM Account ORDER BY Name LIMIT 20";

client.query(query, queryCallback, errorCallback);
client.query(query)
.then(queryCallback)
.catch(errorCallback);
}

Loading