Ad-hoc REST services on the force.com platform
Nicolas Galler | December 5, 2010Note – as of Summer ’11 there is a much better solution in the form of Javascript Remoting. I am leaving the information below for reference but do not recommend using it.
Force.com is coming up with a REST style api to access the data from 3rd party applications, widgets etc. While this is great news as this type of web services is a lot easier to access than traditional SOAP calls from many programming languages (including obviously the important Javascript), it should not be forgotten that it has been possible for a while already to create your own, custom REST-style services – very useful when trying to make a page more responsive by coding certain areas in Javascript with AJAX calls. These don’t benefit from the OAuth authentication so they are more useful for pages that are accessed by already authenticated users. One advantage is that as they are very specialized you can make the payload as lean as necessary. One drawback is that as the facilities of the native Force.com programming environment are a bit rudimentary there is a certain amount of boiler-plate code involved.
The controller side looks like a usual controller, typically using the query-string or form parameters in the constructor to build a result which is then available to the view. The view can loop over that result and output it in JSON format using the built-in JsEncode function. For example here is a simple contact search service:
public with sharing class SearchServiceController {
/**
* Array containing the results.
*/
public Contact[] Matches { get; private set; }
/*
* grab the parameter from the page's and run the search.
*/
public void executeSearch() {
String name = ApexPages.currentPage().getParameters().get('name');
executeSearch(name);
}
/**
* Run the search with the specified parameters, populating the Matches variable.
*/
public void executeSearch(String name){
Matches = [select Id, Name, MailingStreet, MailingCity, Mailing State from Contact where LastName=:name];
}
}
Then the view could look something like this… most modern programming languages have constructs for automatically serializing to JSON nowadays, but not Apex – still, it’s not that hard to get the same result on the view:
<apex:page contentType="text/javascript" controller="ProximitySearchServiceController" action="{!executeSearch}" >
<apex:variable var="rowIndex" value="{!0}"/>
{"result":[
<apex:repeat value="{!Matches}" var="contact" >
<apex:outputText rendered="{!rowIndex != 0}" value=","/>
{"name":"{!JsEncode(contact.Name)}",
"address1":"{!JsEncode(contact.MailingStreet)}",
"city":"{!JsEncode(contact.MailingCity)}",
"state":"{!JsEncode(contact.MailingState)}" }
<apex:variable var="rowIndex" value="{!rowIndex+1}"/>
</apex:repeat>
]}
</apex:page>
Not exactly rocket science, but that’s kind of the point: the beauty of REST is that it simply leverages the existing HTTP protocol without the added baggage (both in payload and complexity) of an RPC protocol. Perhaps the only tricky part in the force.com version is the output of the comma in the right position (remember a trailing comma in a list works fine in FireFox but not in IE). There is no out of the box facility for getting the row index in the repeater. Also, don’t forget to set the contentType so that the default page headers don’t get included. And don’t forget to disable the development mode on the page… other, the HTML for the page editor will still get sent and mess with the JSON output!
Lastly a little security note… such services are not wide open because they require the user to be logged into Salesforce. However, it is possible for an attacker who controls a web site that is visited by a Salesforce user to submit a request on their behalf (including their authentication cookies). They won’t be able to retrieve the results, but if the service causes an update or an insert that could happen. If it’s a concern (e.g. for an ordering system) you can check the HTTP referer using ApexPages.currentPage().getHeaders().get(‘Referer’), and make sure it comes from an expected site / page. Some good notes about that on the force.com blog.





