public String CloudThoughts{ get; set;}
<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
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
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.
<apex:page controller="RESTController" action="{!processRequest}" contentType="application/x-JavaScript; charset=utf-8" showHeader="false" standardStylesheets="false" sidebar="false"> {!JSONResult} </apex:page>
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')); } }