Building Android Applications with the Force.com REST API

Building Android Applications with the Force.com REST API

Abstract

The Force.com REST API provides a powerful new way in which to query and manipulate Force.com data. The simplicity of the standards-based REST API, coupled with the the fact that the client stack needs nothing more than an HTTP library (as opposed to the need for a SOAP runtime for invoking the SOAP API), makes it particularly well suited for mobile applications.

The Android platform has recently exploded in popularity and is now one of the top choices for supporting a mobile experience on Force.com. The Force.com toolkit for Android is the primary tool for any developer wanting to access Force.com data from an Android application. The toolkit exposes a simple interface (login, query, update etc.) for developers to code against and hides the underlying details of connecting and communicating with Force.com. That toolkit, however, uses the SOAP-based Web Services API under the covers.

This article walks you through a sample Android application that uses the REST API to query and manipulate Force.com data. While the article uses Android as an example - you'll be able to apply these techniques on many other mobile platforms.

Prerequisites

This article comes with a sample Android application that demonstrates basic CRUD access using the REST API. The sample was developed on the Android 2.2 Platform (API level 8). This article assumes that you’re using the ADT (Android Development Tools) plugin for Eclipse IDE to do Android development and that the the Android SDK and Eclipse/ADT setup is complete. For detailed instructions on how to download and setup the Android SDK and the Eclipse ADT plugin please refer to the Android SDK website.

This article also assumes basic familiarity with Android development and focuses primarily on the design and implementation of the REST API callouts. If this is your first exposure to Android development, it is highly recommended that you first walk through at least one Android tutorial to get familiar with the basic concepts and architecture of the platform. The Hello World tutorial is a good place to start.

Example Application Overview and Installation

This section shows how to install the example application. The next section provides a demo, while the rest the article provides a code walk through - illustrating the basics of interacting with the API.

The app provides basic CRUD access to the standard Account object using the REST API. It starts by querying 20 Account records via the API (after completing the OAuth 2.0 authentication). These records are displayed in a simple 'List' view. The user can create a new Account record from this page by clicking the ‘New’ button. Clicking on an individual Account record brings up the respective Account Details. From here, the user can choose to update or delete the Account record by clicking the respective buttons. The Android app uses the REST API to perform all CRUD operations.

Installing the sample application in Eclipse

First, download and unzip sample ZIP file - to a local directory. Next, create a new Android Project and import the sample application.

1) In Eclipse, click on File-->New-->Other-->Android Project. Select ‘Create Project from existing source’ and select the local directory where you unzipped the sample application.

2) Select an appropriate build target environment and hit Finish


Importing sample in Eclipse

OAuth Setup

The REST API supports OAuth 2.0 for authenticating with Force.com (in addition to the standard username/password based Session Id ). The next step in our setup is therefore to complete the OAuth 2.0 setup in your Force.com environment. This requires registering a new Remote Access client in your Salesforce Org by going to Setup-->Develop-->Remote Access-->New.


Creating a new Remote Application

You can name the application as you like, but the callback URL is important and will be referenced later in the setup. Note that you don’t have to set the callback URL to ‘sfdcsample:success’ but if you decide to change it, you’ll need to update the sample Android application (more on this later).

Once you create a new Remote Access application, you'll be assigned a Consumer Key and Consumer Secret (this is part of the OAuth 2.0 protocol). Make note of the Consumer Key as you’ll need it in a later step (the Consumer Key is blacked out in the screenshot below for privacy reasons).

Acquiring the Consumer Key

Updating the Android application

The next step is to update the Android application to use the Consumer Key that was generated above. Edit the strings.xml file that is located in the res/values directory and set the value of the 'consumerKey' string to the Consumer Key that was generated in the previous step.

    <string name="consumerKey">Enter your Consumer Key here</string>

Note that if you set the Callback URL in the previous step to something other than ‘sfdcsample:success’, you’ll need to update the 'callbackUrl' string in this file accordingly. Lastly, if connecting to a Sandbox Org, update the 'oAuthUrl' string to 'https://test.salesforce.com'.

Application Demo

With the preliminary setup complete, let’s take the sample app for a spin.

To launch the application, select Run--> Run in Eclipse and select ‘Android Application’. This will launch the Android Emulator. After unlocking the screen (just drag the lock icon across the screen), the sample application will automatically launch. The first step is to initiate the OAuth authentication by having the user log into his org.


OAuth login


After entering your credentials, you’ll be asked to approve access for the Remote Access Application that you had setup previously (‘AndriodTest’).


OAuth authorization


After approving the application, you should be presented with a list of Accounts from the org that you logged in with.


List of Accounts


Clicking on the ‘New’ button brings up the screen to add a new Account


Adding a new Account


Similarly, you can view individual Account details by clicking on the respective Account name in the list view and update and delete the Account from the detail view.

Code Walkthrough

Now, let’s review the application and its use of the REST API to perform the CRUD operations.


OAuth authentication

Let’s start by reviewing how the application acquires an OAuth 2.0 access token that is necessary to make any REST API call.

Note: Though the REST API also supports username/password based Session IDs for authentication, it is highly recommended that you use OAuth 2.0 for your mobile applications. The OAuth 2.0 protocol is optimized for mobile and Web 2.0 applications and is better than the alternative, which is to acquire a Session ID by invoking the 'login' method of the standard Salesforce SOAP API.

Before we review the Android code however, it is important to understand the overall OAuth 2.0 User-Agent flow that is implemented in the sample application.

OAuth 2.0 User-Agent flow

The standard Salesforce help offers a more detailed overview of the flow here. As described in the documentation, the user-agent flow (which is one of the three OAuth 2.0 flows that the platform supports) is primarily used by client mobile applications like Android, iOS and Blackberry. In a nutshell, the OAuth 2.0 user-agent flow starts with the client application (in this case our Android app) directing the user to Force.com to authenticate and authorize the application. Once the user logs into Force.com and authorizes the application, Force.com makes a call back to the client application and passes along an access token (among other things). The client application then uses the access token to make all subsequent calls to Force.com.

Let’s now walk thru how the Android application implements this flow.

	WebView webview;
	String callbackUrl;	

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.main);
        
        String consumerKey = this.getResources().getString(R.string.consumerKey).toString();
        String url = this.getResources().getString(R.string.oAuthUrl).toString();
        callbackUrl = this.getResources().getString(R.string.callbackUrl).toString();
        
        String reqUrl = url + 
                 "/services/oauth2/authorize?response_type=token&display=touch&client_id="
                 + consumerKey + "&redirect_uri=" + callbackUrl;
        
        webview = (WebView) findViewById(R.id.webview);
        
        webview.setWebViewClient(new HelloWebViewClient(this));
        
        webview.getSettings().setJavaScriptEnabled(true);
        webview.loadUrl(reqUrl);
    }
    
       
    private class HelloWebViewClient extends WebViewClient {
        
    	Activity act;
    	public HelloWebViewClient(Activity myAct) {
    		act = myAct;
    	}
    	
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            
	        Log.d("Sfdc-sample", "Redirect URL: " + url);
	        if (url.startsWith(callbackUrl)) {
        		parseToken(url);
        		Intent i = new Intent(act, AccountListView.class);
        		startActivity(i);
	            return true;
	        } else {
	        	return false;
	        }
        }

The ‘SfdcRestSample.java’ Activity is the primary entry point for the application (this is specified in the AndroidManifest.xml file) and as per the Android Activity lifecycle, the ‘onCreate’ method is called when the application first launches. In it, we first direct the user to the OAuth authorization endpoint. One of the parameters passed to the authorization endpoint is the Consumer Key that was assigned to the Remote Access application. This is how Force.com knows which Application is requesting access to the user’s data. In addition, we pass along the redirect URI that was setup in the Remote Access application. Force.com will redirect the user to this URI after s/he has successfully authenticated. Notice also the ‘display=touch’ parameter in the authorization URL. This tells Force.com to present a mobile-optimized OAuth authorization page to the user.

Those familiar with OAuth 2.0 may also notice that we only pass along the Consumer Key, but not the Consumer Secret. This is one of the key differences between the OAuth 2.0 Web Server authentication flow and the user-agent flow that we use for a mobile device such as Android.

Once the authorization URL is constructed with the appropriate parameters, we direct the user to the URL by calling the standard ‘loadURL’ method.

Note the use of the WebViewClient class to override the default handler for the URL. This allows us to receive notifications and requests connected to the authorization URL. In our case, we override the ‘shouldOverrideUrlLoading’ method which is called when ‘a new URL is about to be loaded in the current WebView’ – which is exactly what happens when Force.com redirects the user back the mobile client after a successful authentication. In this method we first check for the Redirect URI specified in the original authorization request. Since only Force.com would know this callback URI, we can be assured that the redirect/callback was in fact from Force.com and not from a foreign/rogue endpoint.

The rest of the class (not shown above) parses out the various values returned by Force.com as per the OAuth 2.0 protocol – principally the ‘access_token’. These values are stored in a simple DAO wrapper class (OAuthTokens.java). The GlobalState.java class extends the ‘Application’ base class. Extending the ‘Application’ base class is a way of maintaining global application state in Android and since we’ll need the OAuth access token for all subsequent REST API calls, we store it in the GlobalState.java class.

Querying data using the REST API

Let’s next review the ‘AccountListView.java’ Activity class which is where we make the call to retrieve Account data.

	private void getAccountData() {
		GlobalState globalState = (GlobalState) getApplication();
		OAuthTokens myTokens = globalState.getAccessTokens();
		
		DefaultHttpClient client = new DefaultHttpClient(); 
		String url = myTokens.get_instance_url() + "/services/data/v20.0/query/?q=";
		String soqlQuery = "Select Id, Name, BillingStreet, BillingCity, BillingState From Account limit 20";
		
		try
		{
			url += URLEncoder.encode(soqlQuery, "UTF-8");
		}
		catch(UnsupportedEncodingException e){}
		
		HttpGet getRequest = new HttpGet(url);
		getRequest.addHeader("Authorization", "OAuth " + myTokens.get_access_token());
		
		try {
			HttpResponse response = client.execute(getRequest);
			
			String result = EntityUtils.toString(response.getEntity()); 
	
			JSONObject object = (JSONObject) new JSONTokener(result).nextValue();
			JSONArray records = object.getJSONArray("records");
			
			globalState.setAccountNames(new String[records.length()]);
			globalState.setAccounts(new JSONObject[records.length()]);
			
			for (int i=0;i<records.length();i++) {
				JSONObject record = (JSONObject) records.get(i);
				String accountName = record.getString("Name");
				globalState.getAccountNames()[i] = accountName;
				globalState.getAccounts()[i] = record;
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (JSONException e) {
			e.printStackTrace();
		}	
	}

As expected, the code to invoke the REST API and query a set of Account records is very simple. To execute a SOQL query using the REST API, the code makes a GET request to the ‘/services/data/vXX.X/query/’ URI passing the actual query as a URL Encoded ‘q’ parameter. In addition, we set the ‘Authorization’ header to the OAuth access token. Though the REST API supports both XML and JSON formats, we’ve chosen to accept JSON data (the default). The remaining code makes a GET request to the REST API, parses the Account records returned in the JSON response and stores them in the GlobalState.java class so that they can referenced in other Activities of the application.

Note that though this is not included in the sample application, you can also query an individual SObject record by making a GET request to the ‘/services/data/vXX.X/ sobjects/<SObject API Name>/<Record Id>’ URI and passing along an optional list of SObject fields in the ‘fields’ parameter (e.g. - ‘/services/data/v20.0/sobjects/Account/<Record Id>?fields=AccountNumber,BillingPostalCode)

Inserting data using the REST API

The ‘AddAccount.java’ class is the Android Activity (i.e. screen) associated with creating a new Account and encapsulates the logic for inserting a new Account record using the REST API.

        	OAuthTokens myTokens = globalState.getAccessTokens();

    		String url = myTokens.get_instance_url() + "/services/data/v20.0/sobjects/Account/";
			HttpPost post = new HttpPost(url);
				
			JSONObject data = new JSONObject();

			data.put("BillingStreet", mAccountBillingStreetEditText.getText().toString());
			data.put("BillingCity", mAccountBillingCityEditText.getText().toString());
			data.put("BillingState", mAccountBillingStateEditText.getText().toString());
			data.put("Name", mAccountNameEditText.getText().toString());
				
			StringEntity se = new StringEntity(data.toString());
			post.setEntity(se);
			post.setHeader("Authorization", "OAuth " + myTokens.get_access_token());
			post.setHeader("Content-type", "application/json");
				
			DefaultHttpClient client = new DefaultHttpClient();
        	HttpResponse resp = client.execute(post);
	        	
			String result = EntityUtils.toString(resp.getEntity()); 
        	Log.d(TAG, result);
			JSONObject res = (JSONObject) new JSONTokener(result).nextValue();
			String id = res.getString("id");
			Log.d(TAG, "Salesforce id:"+id);


To insert a record using the REST API, the code executes a POST request to the ‘/services/data/vXX.X/sobjects/<SObject API Name>/’ URI passing the record data (in JSON format) in the request body.

Updating data using the REST API

The ‘UpdateAccount.java’ class is the Android Activity associated with updating an Account record using the REST API.

    		OAuthTokens myTokens =globalState.getAccessTokens();
    		
    		String url = myTokens.get_instance_url() + "/services/data/v20.0/sobjects/Account/"+acct.getString("Id")+"?_HttpMethod=PATCH";
			HttpPost post = new HttpPost(url);
				
			JSONObject data = new JSONObject();

			data.put("BillingStreet", mAccountBillingStreetEditText.getText().toString());
			data.put("BillingCity", mAccountBillingCityEditText.getText().toString());
			data.put("BillingState", mAccountBillingStateEditText.getText().toString());
			data.put("Name", mAccountNameEditText.getText().toString());
				
			StringEntity se = new StringEntity(data.toString());
			post.setEntity(se);
			post.setHeader("Authorization", "OAuth " + myTokens.get_access_token());
			post.setHeader("Content-type", "application/json");
				
			DefaultHttpClient client = new DefaultHttpClient();
        	client.execute(post);

To update a record using the REST API, the code executes a PATCH request to the ‘/services/data/vXX.X/sobjects/<SObject API Name>/<Salesforce ID>’ URI passing the record data (in JSON format) in the request body.

Since the PATCH method is a relatively new addition to the HTTP standard, many HTTP libraries (including the Apache library included in Android) don’t support it yet. This problem can easily be circumvented by using the regular POST method and passing along a ‘_HttpMethod=PATCH’ query string parameter as the code does.

Deleting data using the REST API

The ‘AccountDetail.java’ class includes the code to delete an Account record using the REST API.

	protected void deleteAccount() {
		OAuthTokens myTokens = gs.getAccessTokens();
 		JSONObject acct = gs.getSelectedAccount();
 		
        try {
			String url = myTokens.get_instance_url() + "/services/data/v20.0/sobjects/Account/"+acct.getString("Id");
			HttpDelete del = new HttpDelete(url);

			del.setHeader("Authorization", "OAuth " + myTokens.get_access_token());
			del.setHeader("Content-type", "application/json");

			DefaultHttpClient client = new DefaultHttpClient();
			client.execute(del);

        	Intent i = new Intent(this, AccountListView.class);
            startActivity(i);
		} catch (JSONException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		finish();
    }	

To delete a record using the REST API, the code executes a DELETE request to the ‘/services/data/vXX.X/sobjects/<SObject API Name>/<Salesforce ID>’ URI.

Error Handling

As with any API, an important consideration when using the REST API is how to handle errors. As with every other API supported by Force.com, any data inserted/updated/deleted via the REST API has to pass all data integrity and validation rules. This includes any validation rules, Apex triggers and Workflow Rules that are configured for the respective SObject. If any of those fail, a 400 HTTP error will be returned by the API. The following code snippet from the ‘AddAccount.java’ class shows how to handle an exception when inserting an Account record.

        	if (resp.getStatusLine().getStatusCode() == 400)
        	{
        		JSONArray value = (JSONArray)new JSONTokener(result).nextValue();
        		JSONObject object = (JSONObject)value.get(0);
        		String errorCode = object.getString("errorCode");
        		if (errorCode != null)
        		{
            		errorMsg = object.getString("message");
            		showDialog(1);
            		return;
        		}
        	}

We start by checking for the 400 error code in the API response. We then parse the JSON response to extract the error code and error message. A sample JSON error response looks something like this:

[ {

 "fields" : [ "BillingState" ],
 "message" : "Billing State is required",
 "errorCode" : "FIELD_CUSTOM_VALIDATION_EXCEPTION"

} ]

Once we’ve extracted the error message, we display it to the user using a standard Android AlertDialog. To test this error handling logic, try and add a new Account record without specifying the Account Name (which is a required field).

Summary

This article walked through the setup, design and code for a sample Android application that uses the REST API to perform basic CRUD operations. The application includes the plumbing for getting an OAuth 2.0 access token which is required for making REST API calls.

REST API Quick Reference

The following is quick guide to various URIs supported by the REST API.

Resource Name URI Description
Versions / Lists summary information about each Salesforce.com version currently available, including the version, label, and a link to each version's root.
Resources by Version /vXX.X/ Lists the resources available for the specified API version. It provides the name and URI of each resource.
Describe Global /vXX.X/sobjects/ Lists the available objects and their metadata for your organization's data.
SObject Basic Information /vXX.X/sobjects/SObject/ Describes the individual metadata for the specified object.
SObject Describe /vXX.X/sobjects/SObject/describe/ Completely describes the individual metadata at all levels for the specified object.
SObject Row /vXX.X/sobjects/SObject/id/ Accesses individual records from an object based on the specified object ID. You can retrieve or update individual records within a specific object, or delete the specified object.
SObject Blob Retrieve /vXX.X/sobjects/SObject/id/blobField Retrieves the specified blob field from an individual record.
Query /vXX.X/query/?q=soql Executes the specified SOQL query.
Search /vXX.X/search/?s=sosl Executes the specified SOSL search. The search string must be URL-encoded.

See the Force.com REST API Developer's Guide for full details of each resource.

References

About the author

Sandeep Bhanot is a Developer Evangelist with Salesforce.com. He had asked Santa for a EVO 4G Android phone for Christmas.