Sunday, September 22, 2013

Salesforce REST Exceptions

I get a lot of emails from people working with the Salesforce REST who say that they are getting a 400 error (Bad Request) when trying to perform one of the API functions. In this article I will talk about this error and how to troubleshoot it as well as other API errors.
For the purpose of this article I will assume you are using an HttpWebRequest object to make your requests to Salesforce. The function on HttpWebRequest that does the actual work is  GetResponse. This function makes the call to the remote server and retrieves the response. If anything goes wrong with a REST API request on the Salesforce server it will generate an 400 HTTP error response code and then GetResponse will throw a WebException containing that status code. The 400 response code isn’t too useful since there are a lot of things that can cause it, but if you catch the exception you can still access the response stream which will contain a JSON object with more details.
As an example, if we make a call to get an Access Token and pass an incorrect client_secret you will get this web exception:
"The remote server returned an error: (400) Bad Request."
If we then get the response stream we find this:
{\"error\":\"invalid_client\",\"error_description\":\"invalid client credentials\"}
Here is another example. If we issue a query command with a syntax error in the SOQL query (SELEC id,accountNumber,name from account), you will get this:
{ \"message\" : \"unexpected token: SELEC\",\n  \"errorCode\" : \"MALFORMED_QUERY\"}
You can see that it didn’t recognize “SELEC” since it is missing the ‘T’. Note that the format of the JSON in this message is different then the first one.
So what is the best way to handle this? There are a number of options depending on you needs, but here is one suggestion. Here is the piece of code that makes the web request that would be in a library used by all Salesforce REST calls. ‘req’ is  a HttpWebRequest object.

req.Method = "GET";
System.Net.WebResponse resp = null;
try
{
    resp = req.GetResponse();
}
catch (WebException ex)
{
    string msg = "";

    if (ex.Status == WebExceptionStatus.ProtocolError)
    {
        resp = ex.Response;
        msg = new System.IO.StreamReader(resp.GetResponseStream()).ReadToEnd().Trim();
    }

    throw new SalesforceException(msg, ex);
}


In the try block we make the call to Salesforce and get the response. Next we catch only WebExceptions, other exceptions are allow to percolate up to the next level which is a good practice for library functions. Next we check that status of the WebException. There are a lot of things that can cause WebExceptions but most of them will result in a response not being returned, so we just look for a ProtocolError. If we do have a protocol error we retrieve the JSON error message from the response. Finally we create and throw a custom exception I call SalesforceException that will hold both the JSON message and the original exception in the InnerException. The code for the SalesforceExpcetion is here:


public class SalesforceException : Exception 
{
    public SalesforceException(string message, Exception innerException)
        : base(message, innerException) { }
}


One other thing to note about Salesforce REST errors. Since REST commands are based on URIs, if you have an error in the URI you will normally get back a HTTP 404 error instead of a 400 error. For example if we send a read command with an invalid object ID in the URI, we will get a 404 error instead of a 400 error.

Saturday, June 8, 2013

Windows 8 + Salesforce.com Part 5: Value Converters

One of the nice features of XAML is it’s extremely flexible data binding capabilities. In previous posts I have been showing how to build a Windows 8 application to display data from Salesforce.com and I use data binding to display the data. XAML doesn’t limit you to just binding text values, you can bind to pretty much any property on a control.
In the Salesforce example I have been developing I display the account data in a tiled gird view. Lets say we wanted to change the color of the tile based on the Priority field in the Salesforce account record. If that field contained a color value we could bind it directly to the Background property of the tile, but you normally wouldn’t have a color value in a data record. In this case the field contains the text values High, Medium or Low. Fortunately, XAML provides a solution to this, value converters.
Value converters simply take one value as an input and return a different value that may even be of different data type. Here is a the converter I created to convert the Priority field value into a color.

public class AccountPriorityConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, string language)
    {
        switch ((string)value)
        {
            case "High":
                return new Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.Colors.Green);
            case "Medium":
                return new Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.Colors.Yellow);
            case "Low":
                return new Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.Colors.Red);  
            default:
                return new Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.Colors.LightGray);
        } 
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

Value converters are classes that implement the IValueConverter interface which has two functions, Convert and ConvertBack. Convert converts the value from your data source into a value that can be used by a XAML property. ConvertBack is needed when you are doing two way binding and need to convert a XAML property back to a value needed by your data source, you will usually not need to implement this function.

Now lets look back at Convert. The first parameter is the value that needs to be converted. Note that it is type object so you will need to cast it to the proper data type. Most of the time you will only need to use this first parameter, the remaining three are used in special situations. The targetType parameter specifies the type you need to convert to. Usually you will know ahead of time what type you are converting to, but there may be special cases when you need this. The third parameter is called parameter and allows you to pass a value from your XAML markup into the converter. For example you could use this to pass in a format string so a string value can be formatted differently in different bindings. The final parameter, language, is used when you do internationalized applications.

In the Convert function I first cast the value to a string then in  a switch statement I return a different colored Brush for each of the Priority values.

To use the value converter we must first declare it on the page were we want to use it. This is done by adding the following line to the <Page.Resources> section of the XAML markup:

<local:AccountPriorityConverter x:Key="PiorityConverter" />

AccountPriorityConverter is the name of the class we just created and PriorityConverter will be the name we use in this page to refer to it. Finally in the DataTemplate for the account items the static value for Background property is changed to bind to the CustomerPriority property using the converter:

<StackPanel Orientation="Vertical" Width="200" Height="200"  Background="{Binding CustomerPriority__c,  Converter={StaticResource PiorityConverter}}"  >

In the binding statement we start with the property we want to bind to, in the case CustomerPriority__c which will contain a string value with the priority. In the Converter attribute we refer to the PriorityConverter resource we specified in the <Page.Resources> section. This converter will take the priority string, convert it to a Brush object which is then assigned to the Background of the StackPanel.

Now when we run the program instead of every item being the same color, they are colored based on the priority.

image


You can download the complete code for this project here:


https://sites.google.com/site/danlboris/SalesforceDemo_Part5.zip