# Friday, 28 May 2010
A true REST interface with full support for HTTP Verbs, status codes, and URIs is currently not available on the Salesforce.com platform. However, a simple REST-like interface for getting objects can be developed using Salesforce Sites, Visualforce, and Apex.

This example uses a free Developer Edition with a Site named 'api' that uses only 2 Visualforce pages named 'rest' and 'error'. The rest page accepts a single parameter named 'soql', executes the SOQL query, and returns a JSON formatted response.



The error page is also used to generically handle all 40x and 50x errors.



The body of the error page returns a simple JSON message that the api is unavailable.
<apex:page contenttype="application/x-JavaScript; charset=utf-8" 
showheader="false" standardstylesheets="false" sidebar="false">
{"status": 500, "error": "api currently not available"}
</apex:page>

The rest Visualforce page (full source at bottom of this post) accepts a SOQL parameter and returns JSON results. To get a list of all Leads with their First and Last names, you'd use the SOQL

select Id, FirstName, LastName from Lead
and pass this query to the REST interface in a GET format such as (example here)
http://cubic-compass-developer-edition.na7.force.com/api?soql=select%20Id,%20FirstName,%20LastName%20from%20Lead

Note that the rest page is defined as the default handler for the site named 'api', so it's not required in the URL.
This simple interface supports any flavor of SOQL, including the WHERE and LIMIT keywords, so you can pass queries like

select Id, FirstName, LastName from Lead where LastName='Smith' limit 20
REST interfaces often assume the unique ID of an object is the last portion of the URL request. This can similarly be achieved with a query like (example here)
select Id, FirstName, LastName from Lead where Id='00QA00000019xkpMAA' limit 1

All of these example queries will only return the Id field by default. To fix this, update the Sites Public Access Settings and grant Read access to the Lead object.





The new URL rewriting feature in Summer 10 provides some additional options the necessary means to implementing a RESTful interface with full support for object URIs and linking.

Visualforce Source Code for rest.page
<apex:page controller="RESTController" action="{!processRequest}" 
contentType="application/x-JavaScript; charset=utf-8" showHeader="false" 
standardStylesheets="false" sidebar="false">
{!JSONResult}
</apex:page>
Apex Source Code for RESTController.cls
public with sharing class RESTController {
	public void processRequest(){
		validateRequest();		
    	if( HasError )
    		return;
    	
    	//Add support for other types of verbs here
    	processGetQuery();
    }
    
    static final string ERROR_MISSING_SOQL_PARAM = 'Bad Request. Missing soql parameter';
    static final string ERROR_SOBJECT_MISSING	 = 'Bad Request. Could not parse SObject name from SOQL';
    static final string ERROR_FROM_MISSING		 = 'Bad request. SOQL missing FROM keyword';
    public void validateRequest(){
    	if(Query == null){
    		errorResponse(400, ERROR_MISSING_SOQL_PARAM);
    	}
    	else if(sObjectName == null){
    		//Force a get of object name property.
    		//Detailed error response should already be logged by sObjectName parser
    	}
    }
    
    public boolean HasError = False;
    private void errorResponse(integer errorCode, string errorMessage){
    	JSONResponse.putOpt('status', new JSONObject.value(errorCode));
    	JSONResponse.putOpt('error', new JSONObject.value(errorMessage));
    	HasError = True;
    }
        
    public void processGetQuery(){
    	Map<String, Schema.SObjectField> fieldMap = Schema.getGlobalDescribe().get(SObjectName).getDescribe().fields.getMap();
    	List<JSONObject.value> objectValues = new List<JSONObject.value>();
    	List<sObject> resultList = Database.query(Query);
 		
    	for(sObject obj : resultList){
    		JSONObject json = new JSONObject();
    		json.putOpt('id', new JSONObject.value( obj.Id ));
    		for(SObjectField field : fieldMap.values() ){
    			try{
    				string f = field.getDescribe().getName();
    				string v = String.valueOf( obj.get(field) );
    				json.putOpt(f, new JSONObject.value( v ));
    			}
    			catch(Exception ex){
    				//Ignore. Field not included in query
    			}
    		}
			objectValues.add(new JSONObject.value(json));
    	}
    	JSONResponse.putOpt('status', new JSONObject.value(200));
    	JSONResponse.putOpt('records', new JSONObject.value(objectValues));
    }
    
    private string m_query = null;
    public string Query{
    	get{
    		if(m_query == null && ApexPages.currentPage().getParameters().get('soql') != null){
    			m_query = ApexPages.currentPage().getParameters().get('soql');
    		}
    		return m_query;
    	}
    }

	static final string SOQL_FROM_TOKEN = 'from ';    
    private string m_sObject = null;
    public string sObjectName{
    	get{
    		if(m_sObject == null && Query != null){
    			string soql = Query.toLowerCase();
    			
    			integer sObjectStartToken = soql.indexOf(SOQL_FROM_TOKEN);
    			if(sObjectStartToken == -1){
    				errorResponse(400, ERROR_FROM_MISSING);
    				return null;
    			}
    			sObjectStartToken += SOQL_FROM_TOKEN.length(); 
    			
    			integer sObjectEndToken = soql.indexOf(' ', sObjectStartToken);
    			if(sObjectEndToken == -1)
    				sObjectEndToken = soql.length();
    			
    			m_sObject = Query.substring(sObjectStartToken, sObjectEndToken);
    			m_sObject = m_sObject.trim();
    			system.debug('m_sObject = ' + m_sObject);
    		}
    		return m_sObject;
    	}
    }
    
    private JsonObject m_jsonResponse = null;
    public JSONObject JSONResponse{
    	get{
    		if(m_jsonResponse == null)
    			m_jsonResponse = new JSONObject();
    		return m_jsonResponse;
		}
		set{ m_jsonResponse = value;}
	}
    
	public String getJSONResult() {
    	return JSONResponse.valueToString();
	}
	
	public static testMethod void unitTests(){
		RESTController controller = new RESTController();
		controller.processRequest();
		system.assertEquals(True, controller.HasError);
		system.assertEquals(True, controller.JSONResponse.has('status'));
		system.assertEquals(400, controller.JSONResponse.getValue('status').num);
		system.assertEquals(True, controller.JSONResponse.has('error'));
		system.assertEquals(ERROR_MISSING_SOQL_PARAM, controller.JSONResponse.getValue('error').str);
		
		controller = new RESTController();
		ApexPages.currentPage().getParameters().put('soql', 'select Id fro Lead');
		controller.processRequest();
		system.assertEquals(True, controller.HasError);
		system.assertEquals(True, controller.JSONResponse.has('status'));
		system.assertEquals(400, controller.JSONResponse.getValue('status').num);
		system.assertEquals(ERROR_FROM_MISSING, controller.JSONResponse.getValue('error').str);
		
		controller = new RESTController();
		ApexPages.currentPage().getParameters().put('soql', 'select Id from Lead');
		controller.processRequest();
		system.assertEquals(False, controller.HasError);
		system.assertEquals('Lead', controller.sObjectName);
		
		Lead testLead = new Lead(FirstName = 'test', LastName = 'lead', Company='Bedrock', Email='fred@flintstone.com');
        insert testLead;
        
        controller = new RESTController();
		ApexPages.currentPage().getParameters().put('soql', 'select Id from Lead where email=\'fred@flintstone.com\'');
		controller.processRequest();
		system.assertEquals(False, controller.HasError);
		system.assertEquals('Lead', controller.sObjectName);
		system.assertEquals(True, controller.JSONResponse.has('records'));
	}
}
Friday, 28 May 2010 12:34:08 (Pacific Daylight Time, UTC-07:00)
# Saturday, 22 May 2010
The Google I/O Developer Conference this past week (May 19-20) was a highly anticipated event for both Google web and mobile Developers alike.

With the exception of Chrome OS, all of the technologies and products on my watch list unveiled new and exciting features that re-affirmed my belief that Google is indeed one of the leading cloud platforms to be embraced by all cloud Developers.

The marriage between the Android mobile OS and Google services is simply outstanding. The new Web Store works seamlessly with mobile devices and actions taken on either the desktop or mobile are immediately reflected on the other device.

Google handed out 2 mobile phones to attendees, a Motorola Droid and a HTC EVO 4G, and I was amazed at the ease and speed of syncing both devices with my existing Google Premier Apps account.

The dilemma I faced was whether to write mobile apps natively for Android apps or use HTML5. Geolocation, games, and apps requiring haptic response will most definitely be better served running natively on Android. General web sites and marketing centric apps written in HTML5 will enjoy the benefits of running cross platform (iPhone, Blackberry, Android) but will lack high end graphics and GPS support (although SVG and Geo Javascript extensions could address both of these in HTML5).

Developing for Google in previous years has been something of a hobby for many Developers, since there were few monetization opportunities outside AdWords and AdSense. Google unveiled several new monetization platforms for both desktop and mobile developers that will make Android very attractive to existing iPhone developers (plus Google doesn't discriminate apps uploaded to their Marketplace).

With 100K Android phone activations per day it's becoming very easy to do the quick math and trust that Google Android is a viable and profitable distribution vehicle.

A considerable amount of time was spent on Google Business during the day 1 keynote. The Google/VMWare partnership mirrored closely what was announced for VMForce just a couple weeks ago, although I think Salesforce did a much better job of helping Developers understand what was being offered via SpringSource. Google is serious about the business market and wants Java apps written on their platform.

I think the most underrated business feature is Google Apps Script. This is a free extension to Google Premier Apps that enables complex workflows between spreadsheets, web forms, email, and calendars. I would highly advise SMBs to use Apps Script for their business needs while larger Enterprises would probably benefit more from the SpringSource business platform.

All demonstration hiccups aside, the Google TV announcement was interesting from a consumer perspective. It was quite amazing to see Google's CEO on stage with the other CEO's associated with the launch (Sony, Best Buy, Intel, Logitech, and Adobe). That was some serious firepower and, if anything, really reaffirmed that Google is pursuing a stratified and open platform in contrast to Apple's closed platform.

On a technical note, I enjoyed spending some time with the Chrome development team during their open "Office Hours". The conversation with them inspired me to download the V8 Javascript engine and brush up on my C++ skills in order to contribute some JSON parsing enhancements I requested.

Most of what I was hoping for in HTML5 support was either previewed at the conference or is scheduled for delivery this year. The V8 engine is in the Android 2.2 Froyo release and we can expect 2010 to be a milestone year for evolving browser technology.

The unedited YouTube video below is a 10 minute walkthrough of the conference floor with both Hardware and Software vendors showing their wares (check out the Salesforce booth around minute 3).

Saturday, 22 May 2010 17:02:22 (Pacific Daylight Time, UTC-07:00)
# Monday, 17 May 2010

I'm getting on a plane tomorrow morning for San Francisco to attend the Google I/O conference. If you're a cloud developer and can only attend 1-2 conferences per year, then this conference should be on your calendar (in addition to Dreamforce).

Even though 90%+ of Google's revenue comes from search advertising, they are much more than a search engine these days. They've effectively leveraged their massively scalable Google File System to develop and host hundreds (if not thousands) of applications that are accessible throughout the world using nothing but a web browser.

Google has realized that the best way to increase revenue is not to push more customers towards Google, but to provide more accessibility to the web itself. You can deploy this somewhat altruistic strategy when you have a 72% market share.

Deploying highspeed fiber networks and launching the open source Android mobile operating system are just a couple examples of Google seeking to further enable access to the cloud on the premise that consumers of these networks/devices will eventually utilize the Google search engine and ads.

To see Android phone sales surpass iPhone in the last quarter is quite an amazing feat given the OS has only been available for about 18 months. Google shipped Motorola Droids to all 4,000 Google I/O attendees (including myself) with 30 days pre-paid access via Verizon. My Google G1 phone now seems archaic in comparison and I can't wait for the 2 year Sprint subscription to expire so I can switch over to Verizon and continue using this Moto Droid (I also recently purchased a Verizon MiFi for roaming cloud access and have been very impressed with their coverage)

Moving contacts and calendar events to the cloud is a common first step (I still don't understand why iPhone users tolerate the concept of syncing a device) and the ease of using GMail with Android makes it quite easy for consumers and businesses alike to move to the cloud.

Some key areas/topics I'll be following at the conference:

Chrome OS
I think the formal launch of Chrome OS and ubiquitous distribution through netbook partners will be a next likely step to broaden Google's reach and I expect some exciting announcements about this platform this week.

Android Development
I have the beginnings of an Android app integrated with Salesforce Chatter started, but I need to attain more mastery of debugging techniques, use of the emulator, and package/deployment steps.

Google Apps Marketplace
How to develop for and monetize Google App plugins.
Appirio has a pretty slick demo of embedding a Salesforce widget in Google Mail. I'm hoping Google will open up this API at the conference for others to try it out.

IoT and Google App Engine (GAE)
I'm interested in the potential of using GAE and BigTable as an aggregator for the Internet of Things. One side project I'm working on is to port my Chatter bot to Google.

Chrome Browser and HTML5
Just how far can Javascript be pushed to deliver rich internet applications? I'll be looking for some early indications that Google is serious about implementing HTML5 local storage and video on Chrome.

BI / Google Charts / Visualization
This is a little known API for rendering charts using a RESTful interface and I really dig it. There's great potential for moving business intelligence (BI) apps to the cloud by replicating/aggregating data using GAE and Google charts and visualizations for reporting

Google Sites
As a follow-up to our soon to be released "Cool Sites for AppExchange" app, I'm interested to learn how our template designs can be repurposed for Google Sites.

Google Wave
We've started using Google Wave internally quite a bit internally and it's emerging into an excellent collaboration tool.
Check out some live Google Waves this week. I just may be on some of them :-)

Monday, 17 May 2010 10:58:05 (Pacific Daylight Time, UTC-07:00)
# Friday, 14 May 2010

What if the buildings you worked in could participate in Salesforce Chatter feeds? What if the products you shipped could automatically create Cases in Salesforce when they needed servicing? More objects are becoming embedded with sensors and gaining the ability to communicate. This is enabling the next major advancement in the cloud; the Internet of "Things".

Force.com provides an ideal platform for sensor data with the ability to relate information in the physical world to native or custom objects. My previous blog post on Chatter highlighted the Salesforce user experience and ability for people to interact in the cloud. This post demonstrates using Force.com and Chatter to capture information from objects in the physical world and posting to Chatter feeds using the Chatter web services API.

This application is a very basic Facility Management app. There is a single custom object named "Building" that is comprised of many "Assets", such as Conference Room, Main Entry, Air Conditioner, and Heating System. (See this application in action in the video at the end of this blog post).

Sensors on these assets report their readings to Salesforce in the form of Chatter FeedPost records so that when someone walks into a conference room, the Asset record for that room is updated with Chatter information to the effect of "Motion detected in Conference Room".

The feed posts appear to be created by a Salesforce User named "Environment Bot". This is essentially an API user account for reporting environmental sensor activity.

People can comment on the bot's posts. For example, building maintenance personnel may notice the temperature increasing in some rooms and post comments like "Hey, is anyone on this? The AC appears to be broken on the 3rd floor". Or, a night watchman may notice movement around the Main Entry after business hours and log some comments about what he noticed on patrol. Chatter Bot also has the ability to post pictures and share them as links to Chatter Feeds.

Because the facility management application is utilizing the Chatter API, other Chatter enabled apps may be used to augment and enhance the application. For example, installing the Chatter Timelines application from Ron Hess provides a nice linear visualization of what sensor events occurred and when.

The Chatter Bot is built using an Arduino Duemilanove electronics prototyping platform with Ethernet shield and a Radio Shack breadboard with motion and light sensors.

The Arduino sketch source code just runs in a loop polling the sensors and then notifies Salesforce via a proxy service when environmental changes are detected.

I initially designed the Chatter bot to talk directly to the cloud, but later discovered there are more benefits in having bots communicate through a proxy service to Salesforce.

Industry applications
There are a number of possible industry applications that can leverage this framework:

  • Continuous Emissions Monitoring (CEM) Systems
  • Home / Business Alarm Systems
  • Shipment / Automobile location tracking
  • Environmental Control Systems
  • Healthcare Biosensors

If you'd like to learn more about interfacing Salesforce with the physical world via sensors, then please vote for my proposed session "The Chatter of Things" for Dreamforce in December 2010 to see Chatter Bot live and in action.

The number of objects far exceeds the number of people and there is great potential in using Force.com to enable the Internet of Things. There are many more enhancements I'll be making to this platform. I look forward to sharing them.

Video
This video provides a brief demonstration (4:44) of the Facility Management Chatter Bot in action.

Friday, 14 May 2010 09:46:00 (Pacific Daylight Time, UTC-07:00)