Saturday, October 30, 2010

Salesforce.com REST API


A while back I had the opportunity to develop a .NET desktop application that interfaced to Salesforce.com using the SOAP API, so I was very interested when I heard about SFDC's new REST based API. The beta of this interface has just been made available to developers and will eventually go into production in a future release. SFDC has made a simple Java sample available but no .NET samples yet, so I thought I would write an article explaining how to access the API from .NET. This example will be done in C# using Visual Studio 2010 and the .NET Framework 4.0 although there is no reason this couldn't be done with earlier versions of the framework.
To try out the API you will need a Salesforce.com developer account. You can sign up for a free account at http://developer.force.com/. I am not sure if the REST API is automatically enabled for all developer accounts, but if not you can sign up for it here.

Authentication

Before you can use the REST API you need to authenticate to Salesforce.com. There are two ways to do this, using a Session ID from the old SOAP API, or using OAuth which is what I will be doing in this sample. OAuth allows an application to access a web based resource without the user having to provide their login details to the calling application. The exact details of how OAuth works are beyond the scope of this article but you can learn more at ouath.net.
The first step in authentication is to enable the REST interface. To do this log into your SFDC account and select Setup. Under App Setup, select Develop then Remote Access, this will display a list of Remote Access Applications. The list will be empty at this point, so click on New to add a new remote access application.
clip_image002
There are two required fields, the Application name which can be anything of you choosing, and the Callback URL which needs a little explanation. OAuth is primarily designed to be used between two web sites. The web site requesting access will redirect to the SFDC login screen, and when the user has logged in the SFDC web site will re-direct back to the Callback URL you specify. If you are developing a web application this needs to be the URL of a secure (HTTPS) page. In this demo, since we are developing a desktop app, we don’t want to actually redirect so we put in an identifier of our choice that we will catch in our application.
Once you have filled out the form, click Save, then click on the application name on the list. The details you entered will be re-displayed along with the Consumer Key and Consumer Secret which we will need during the authentication process. I created some object level variables to hold this information:
private string clientID = “YOUR CONSUMER KEY";
private string clientSecret = “YOUR CONSUMER SECRET";
private string redirectURL = "resttest:callback";

Since the key and secret are specific to my SFDC account I have omitted them in the demo. You will need to put in the ones from your account.

The next thing we need to do is have our application call the SFDC login page. If this was a web app we could simply re-direct to is, but since this is a desktop app we can use the WinForms WebBrowser control. I added a WebBrowser control to my form and then put the following code in the Form_Load event:

var authURI = new StringBuilder();
authURI.Append("https://login.salesforce.com/services/oauth2/authorize?");
authURI.Append("response_type=code");
authURI.Append("&client_id=" + clientID);
authURI.Append("&redirect_uri=" + redirectURL);
webBrowser1.Navigate(authURI.ToString());



First we build a URL that points to the SFDC login page and includes the Consumer Key (called client_id) and the re-direct URL as query strings. Next we call Navigate on the web browser control to point to this location.
Once the user has entered their credentials using the web browser control it will be re-directed to resttest:callback. We can catch this in the webBrowser_DocumentCompleted event handler:

if (e.Url.AbsoluteUri.StartsWith("resttest:callback"))
{
webBrowser1.Navigate("about:blank");
code = e.Url.Query;
code = code.Substring(6);

GetToken();
}

When the redirect is found the first thing I did was redirect the web browser control to a blank page. This is not necessary but it looks nice. The URL that is returned will look like this:

callback?code=aPrx9vip.t4qSZdAs_DHNIR9mEcerAoVsq.hX9qVAtUNfAibMV8ClSmYxbsxiWb81O8BzgRwLA%3D%3D

We need to get the code query string since this is needed for the next part of the authentication process. The code is only valid for a short time so we need to use it to get an access token which is what we will actually use to do the REST calls. Here is the code to get the token:
private void GetToken() {
string URI = "https://login.salesforce.com/services/oauth2/token";
StringBuilder body = new StringBuilder();
body.Append("code=" + code + "&");
body.Append("grant_type=authorization_code&");
body.Append("client_id=" + clientID + "&");
body.Append("client_secret=" + clientSecret + "&");
body.Append("redirect_uri=" + redirectURL);

string result = HttpPost(URI, body.ToString());

}

This time instead of passing the parameters as query string we will pass them in the body of the post. You can see that we add parameters for the code returned in the last step, the clinet_id (Consumer Key), client_secret (Consumer Secret) and redirect_uri, then call an HttpPost. The HttpPost is simply a wrapper function around a System.Net.WebRequest object. You can see the full code in the download.

The result returned from the post will be the JSON encoded authentication data:

{
\"id\":\"https://login.salesforce.com/id/0axD7230dz0xrrP/x0e7f0D0A039F1y\",
\"issued_at\":\"1288375889300\",
\"refresh_token\":\"5APp8axZfY11MvXxUzgcRXyJ6zGtoLbD66hgHfx97d9Vklp7uFRmB6minfJwRJr_Ea4Zh563C0s_eg==\",
\"instance_url\":\"https://na5.salesforce.com\",
\"signature\":\"W11FfBhvQ1kwXvNsNTas+Gn3812XRmPL2utxxKbEqss=\",
\"access_token\":\"K0DT029060yJrrP!AR4AQJMczwx9435JeGyhsY40M.OM1BJo5c72z9Hb.F6T5lvqX992pt0KPabj8Snx7L1CqaKxUi7wixxcnfIa9UDY1KiXl0fb1\"

}

If you are using .NET Framework 3.5 or 4, the easiest way to parse this is to use a JavaScriptSerializer call from the System.Web.Script.Serialization namespace. First I created a class to put the data into.

public class TokenResponse
{

public string id { get; set; }
public string issued_at { get; set; }
public string refresh_token { get; set; }
public string instance_url { get; set; }
public string signature { get; set; }
public string access_token { get; set; }

}

Then we can use the following code to parse the response. This will convert the JSON into an instance of the TokenResponse class.

JavaScriptSerializer ser = new JavaScriptSerializer();
token = ser.Deserialize<TokenResponse>(result);

Now the authentication process is complete, so we can actually use this token to call a REST function. We start with a wrapper function that does an HTTP GET.

public string HttpGet(string URI, string Parameters)
{

System.Net.WebRequest req = System.Net.WebRequest.Create(URI);
req.Method = "GET";
req.Headers.Add("Authorization: OAuth " + token.access_token );
System.Net.WebResponse resp = req.GetResponse();

if (resp == null) return null;
System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream());
return sr.ReadToEnd().Trim();

}

You will notice that I am adding the access_token we got in the last step as the Authorization header. To actually call this routine we do the following:

string s = HttpGet(token.instance_url + @"/services/data/v20.0/", "");

We are doing the get using the instance URL returned in the last step, and calling the REST function “/services/data/v20.0/”. This will return a list of the available REST resource and will look something like this:

{
"sobjects":"/services/data/v20.0/sobjects",
"search":"/services/data/v20.0/search",
"query":"/services/data/v20.0/query",
"recent":"/services/data/v20.0/recent"
}

So there are the basics of how to get started with the SFDC REST API. You can download the full code in a Visual Studio 2010 here:

Visual Studio 2010 Salesforce REST API Demo

You can find more information on the Developerforce web site:

Getting Started with the Force.com REST API (Java)

REST API Resource Page

REST API Documentation

44 comments:

Pat Patterson said...

Nice work, Dan!

Have you considered submitting this as a recipe at the Force.com cookbook? See Interact with the Force.com REST API from Ruby for an example of the format.

Anonymous said...

Good work! Interested to start working with rest in my org!

Anonymous said...

Dan,

Have you tried to connect to the Force.com REST API from a Silverlight app?

I'm having a bear of a time getting that to work, and I think it's because Silverlight won't let you specify an Authorization header.

Just wondering if you've ever tried it.

Dan Boris said...

I haven't tried this with Silverlight but I don't see why it wouldn't work. I would think doing OAuth authentication from a Silverlight app would be fairly common.

Wayne G said...

Hi Dan,

Do you know if salesforce have released the full version of REST API yet or is it still in beta?

Dan Boris said...

The REST API has been in production since the Spring 2011 release of Salesforce.

Unknown said...
This comment has been removed by the author.
Unknown said...

Thanks that helped :)

Anonymous said...

There don't appear to be any files in the solution download???

Dan Boris said...

I just downloaded and checked the file and it looks ok to me.

Ravi said...

Hi Dan! very nice written article!

How to do the same with API Session ID instead of OAuth tokens? Does it needs to be passed as querystrings similar to the one you have shown in your .NET sample? Can you also share a sample code?

Dan Boris said...

Check out this article:

http://danlb.blogspot.com/2012/05/salesforce-password-login.html

which explains how to do username/password login instead of OAuth.

kris said...

Awesome..You rock..really concise and effective

kris said...

Awesome..You rock..really concise and effective

Shailesh said...

Indeed its really helpful article!!

I would like to know how can we call Apex web services using OAuth?

Thanks!

Dan Boris said...

Here is the documentation on APEX REST API that will show you how to do that.

http://www.salesforce.com/us/developer/docs/apex_rest/api_apex_rest.pdf

navanit said...

Hi DAN can you show to login using session ID?

how does the url change from when using oauth ?

Dan Boris said...

navanit: You can find a post about how to do that here:

http://danlb.blogspot.com/2012/05/salesforce-password-login.html

Ravi said...

Hi Dan! Great work. This is exactly what I am looking for to authenticate and authorize a user from a .NET app using OAuth and REST API.

I was able to use this successfully in my work. Only thing is that every time I launch my app, I am challenged with OAuth authentication. I would like to have the similar behavior as Chatter Desktop which only authenticates and authorizes once till the token expires as configured in that Org. Can you please share some more thoughts to achieve this?

Shailesh said...

Hi Dan,

Thanks for sharing info.
I've a question, How can we access custom field from Lead/Contact section which is been used in formula field in same section?

e.g. If I've Status__c picklist having values high, medium, low and in same section, I've another formula field which displays image w.r.t option selected in picklist.
When I use sObject/describe; it does not shows picklist field but in formula field where I referenced it!

Let me know, how can I access picklist field using REST API?

Thanks!

Dan Boris said...

Shailesh,
I tried the scenario you described and didn't have a problem. The field showed up with object/describe and I was able to read it back just fine.

Kamalakannan said...

Hi Dan,

Thanks for this piece of code. This is what i was looking around for. I tried the same simple example but i face the following problem, your suggestions will help me a lot.

What i did was to add a browser control and then navigate to the OAuth url in this case yammer. Then capture the response. I directly pasted the constructed URL on the naviagate method of the browser.

I want to be able to capture the access token after the user clicks "allow". In the case when i specify the redirect_uri to be an active website like "https://www.google.com" or "https://www.box.com/services/testaxapplication" the event "document completed is returning the URL with the authorization code". But if i specify it as local host it just doesn't return the URL and retains the initial URL that was loaded in the beginning.

Even when i downloaded the example project given here I faced the same issue.

Dan Boris said...

Kamalakannan:

Do you have SSL setup on localhost? Some sites won't do the OAuth redirect to a HTTP: site, it must be HTTPS:

Girish Gangadharan said...

Hi Dan,

When I try to run the first part of your code (after replacing the consumer key and secret with my values, of course), the response I get from SF is this - https://login.salesforce.com/setup/secur/RemoteAccessAuthorizationPage.apexp?source=.

It doesn't return the "code" as expected. Any ideas what I'm missing?

Dan Boris said...

Girish,

In the GetToken function, in this line:

body.Append("redirect_uri = " + redirectURL);

remove the spaces before and after the equals sign. It used to work with the extra spaces but doesn't anymore. More information here:

http://danlb.blogspot.com/2013/01/salesforce-demo-bug.html

Unknown said...

Dan,

Do you have any sample c# code for using the SFDC Rest-Based Bulk API?

Anything at all would be helpful. I can't get past the first step of creating a job. I've used the REST API quite a bit but can't break thru on the bulk api(rest-based, not soap).

Unknown said...

Dan,

Don't think my first post went thru so this is my second attempt. Do you have ANY sample code for using the SFDC Rest-Based Bulk API from c#? I've used the REST API quite a bite but I'm having trouble just getting started with the Bulk API (rest based, not soap).

Andrew said...

Dan, does this code still work for you? Everytime I try and get the token I get a 400 Bad Request from the server. I have tried with and without URL encoding.

Any ideas?

Unknown said...

Hi Andrew,

Dan has already mentioned in a comment before that:
In the GetToken function, in this line:

body.Append("redirect_uri = " + redirectURL);

remove the spaces before and after the equals sign. It used to work with the extra spaces but doesn't anymore. More information here:

http://danlb.blogspot.com/2013/01/salesforce-demo-bug.html

Unknown said...
This comment has been removed by the author.
Unknown said...

Hi Dan,
I am using the REST API in web application but there is no event in web application like "WebBrowserDocumentCompletedEventArgs"

soo what would i do. Coz when i use resttest:callback it works but how i pick the code from url.

plzz plzz help.

Thanks

David Lozzi said...

Fantastic, thank you!!!

Vetriselvan Manoharan said...

At response I am getting the following message "The remote server returned an error: (400) Bad Request." What could the problem?

Dan Boris said...

hari dev, check out this article that I recently posted:

http://danlb.blogspot.com/2013/09/salesforce-rest-exceptions.html

Vetriselvan Manoharan said...

Hi Dan,

What I need to do is, I have list of account and opportunity filled in grid view in my asp.net application. On clicking the account from my application, it should directly redirect to the corresponding account in salesforce without asking username and password. Is this achievable using REST API? If possible how to do it?

Anonymous said...

Nice work!


Unknown said...

Great explanation through this blog. This blog work as a proper guidance of any salesforce developer and developer.

Unknown said...

Awesome Post !!

Do you have similar post for SOAP?

SimonL said...

Hey Dan, Excellent post could you please shed some light on Salesforce session persistence.

SimonL

Unknown said...

How to logout from that browser, i disposed the browser when i again click on login it already having that url, no login screen came.

Unknown said...

Excellent article! We are linking too this particularly great post on our site. Keep up the great writing.
Salesforce Implementation

Unknown said...

Thanks a lot for sharing the amazing post. Must read blog to get useful information.

Salesforce Implementation Services

Karthika Shree said...
This comment has been removed by a blog administrator.
Anonymous said...

Hi Dan,
When I create the new app in Salesforce it wont allow me to put in a dummy callback url. Callback URL: Invalid Protocol: (resttest callback)

ANy ideas?
Thanks,
John