Friday, December 29, 2017

Some utility methods when writing Salesforce APEX code

Purpose of this blog post

When you work with Salesforce APEX language you come across the Salesforce Object Query Language or SOQL. Any non-trivial APEX script will have some SOQL in it. SOQL is like the standard SQL but with some differences which are more suited to accessing and manipulating Salesforce objects and records.

I found that I needed a few things always in APEX scripts and so extracted them into a utility class. This short blog post is about these code snippets which I have collected in my utility class. 

Many of you are seasoned Salesforce professionals, but I thought of putting these simple utility methods on my blog for quick reference when I need them and for others who might shave off some time of their development work.



A note about Salesforce APEX Exceptions

In other programming languages like Java you can throw the provided exceptions like


throw new IllegalArgumentException(...);


So for my utility class, I created a simple exception using an existing APEX exception, like this

public class UtilityException extends Exception{
}

I then use this exception for throwing my custom exception when I catch an APEX exception like DMLException, etc. Or I can throw this custom exception just like I would in a Java based method when some arguments are missing. Do read the link to get a full understanding of APEX exceptions.

Tip: You can also include the above class definition within your Utility class and refer to it in the class. There is no strict requirement for it to be in a separate class file of its own. For readability and good code layout, I prefer to keep it in its own separate class file UtilityException.apxc


Getting all fields of an object for a SOQL Select statement OR Select * for SOQL

The first thing you notice when working with SOQL to select is that there is no SQL equivalent of 'SELECT * FROM ...'. With SQL, using 'Select * From' is so common. 

In SOQL you have to know the fields in an object to use them in your SELECT statement, but what if you just wanted to have all the fields in your statement like the SQL SELECT *. The following method uses the Salesforce API to get you just that.

Tip: Do look up the documentation for Schema as that's what is in use here to get all the fields.


    /**
     * Provides a list of all fields in a Custom Object
     *
     * @param sObjName - custom object name in string format e.g. 'Account'
     * @return - Returns List of all fields in a custom object
     */
    public static List<String> getAllFieldsForSObject(String sObjName){
        if(String.isBlank(sObjName)){
            throw new UtilityException('Argument \'sObjName\' missing. '
                    + 'Custom Object Name is required');
        }
        List<String> fieldList = 
                new List<String>(Schema.getGlobalDescribe()
                                .get(sObjName)
                                .getDescribe()
                                .fields.getMap()
                                .keySet());
        return fieldList;
    }
    /**
     * Provides a SOQL equivalent of the SQL 'SELECT * FROM ..' statement.
     *
     * @param sObjName - custom object name in string format e.g. 'Account'
     * @return - Returns 'SELECT <field1>, <field2>,... FROM sObjName'
     */
    public String getAllFieldsInSOQLSelect(String sObjName){
        if(String.isBlank(sObjName)){
            throw new UtilityException('Argument \'sObjName\' missing. ' 
                    + 'Custom Object Name is required');
        }
        List<String> fieldList = getAllFieldsForSObject(sObjName);
        String fields = String.join(fieldList,',');
        String soqlQuery = 'SELECT ' + fields + ' FROM ' + sObjName;
        return soqlQuery;
    }
    
    //Example usage:
    //String selectSOQL = getAllFieldsInSOQLSelect('Account');

Getting the field type of a custom object

Sometimes, you have to know the data type of a field in a custom object. Well, you can see your custom object with all its fields and relationships in the Salesforce org UI, but when writing APEX scripts or when using the Salesforce SOAP API, you want to know the field type.

I needed to get a simple idea if a field was a String, a Number, a Date or a DateTime. So I wrote this simple method which does the job. You can always improvise on it, but do let me know so that I can post it here and also use it for my work :)



/**
 * Provides the type of a field on a custom object. 
 * 
 * @param sObjName - custom object name in string format e.g. 'Opportunity'
 * @param fieldName - custom object field name in string format e.g. 'Area__c'
 * 
 * @return - Returns 'STRING' or 'DATE' or 'DATETIME' or 'NUMBER'
 */ 
public static String getFieldType(String sObjName, String fieldName){
    String fieldType = '';
    
    if(String.isBlank(sObjName)){
        throw new UtilityException('Argument \'sObjName\' missing. ' 
                    + 'Custom Object Name is required');
    }
    if(String.isBlank(fieldName)){
        throw new UtilityException('Argument \'fieldName\' missing. ' 
            + 'Custom Object Field Name is required');
    }
    
    Schema.SObjectType objType = Schema.getGlobalDescribe().get(sObjName);
    Schema.DescribeSObjectResult descObjResult = objType.getDescribe();
    Schema.DescribeFieldResult field = descObjResult.fields.getMap()
                                        .get(fieldName)
                                        .getDescribe();
    
    if(field.getType() == Schema.DisplayType.DATE){
        fieldType = 'DATE';
    } else if(field.getType() == Schema.DisplayType.DATETIME){
        fieldType = 'DATETIME';
    } else if(field.getType() == Schema.DisplayType.DOUBLE || 
              field.getType() == Schema.DisplayType.INTEGER){
        fieldType = 'NUMBER';
    } else if(field.getType() == Schema.DisplayType.ADDRESS || 
              field.getType() == Schema.DisplayType.STRING || 
              field.getType() == Schema.DisplayType.PHONE ||
              field.getType() == Schema.DisplayType.TEXTAREA ||
              field.getType() == Schema.DisplayType.PICKLIST){
                  fieldType = 'STRING';
              }
    return fieldType;
}



Finding the duration between two dates

This is a standard requirement in many programming tasks to calculate the duration between two dates or the time elapsed between two dates. Other programming languages like Java have many utilities but here is something I wrote for APEX.

There are two main data types in APEX to deal with date and time - Time and DateTime. I have used these to come up with these utility methods. Do read up on these and you might get some more utility methods out of it.



/**
 * Provides the Time between two times - startTime and endTime
 * @param startTime - the start time
 * @param endTime - the end time
 * @return - the duration between two Time instances 
 */
public static Time GetTimeBetween(Time startTime, Time endTime){
    if(startTime == null || endTime == null){
        return Time.newInstance(0, 0, 0, 0);
    }
    
    Integer elapsedHours = endTime.hour() - startTime.hour();
    Integer elapsedMinutes = endTime.minute() - startTime.minute();
    Integer elapsedSeconds = endTime.second() - startTime.second();
    Integer elapsedMiliseconds = endTime.millisecond() - startTime.millisecond();
    
    return Time.newInstance(elapsedHours, elapsedMinutes, 
                    elapsedSeconds, elapsedMiliseconds);
}

/**
 * Provides the Time between two DateTimes - startTime and endTime
 * @param startDate - the start date
 * @param endDate - the end date
 * @return - the duration between two DateTime instances
 */
public static Time GetTimeBetweenDates(DateTime startDate, DateTime endDate){
    if(startDate == null || endDate == null){
     return Time.newInstance(0, 0, 0, 0);
    }
    return GetTimeBetween(startDate.time(), endDate.time());
}

//Example Usage:
//DateTime startDate = DateTime.newInstance(2017, 12, 29, 20, 30, 00);
//DateTime endDate = DateTime.newInstance(2017, 12, 29, 21, 45, 00);
//Time duration = GetTimeBetweenDates(startDate, endDate);
//System.debug('Duration:' + duration); <-- Duration:01:15:00.000Z


Do let me know if you have some of your own  APEX tips and tricks to share.

Happy APEX coding :) 

Monday, November 20, 2017

Spring Boot RestTemplate to call Salesforce REST API

Purpose of this blog post

Using Spring Boot RestTemplate to communicate with a REST API is nothing new. There are many examples on the net. Using RestTemplate to communicate with a Salesforce REST API is also not  new and there are many examples out there. This post is an attempt to share my learnings with many others who are not new to Spring Boot RestTemplate but maybe relatively new to the Salesforce REST API. Its my attempt to share the things I discovered and provide a quick way to accomplish this REST based communication.

Example Scenario

You have written a REST API in your Salesforce instance to get details of Accounts. You now want to use an external host like a Heroku hosted java application to query this API and get the results.

Prerequisites

I am assuming you are quite comfortable with Java and Spring Boot. I further assume that you are familiar with Salesforce and can find your way by reading the online documentation and help topics published by Salesforce.

Java

You know what you need, but I will list what I used
  • Spring STS IDE
  • Java 8
  • Spring Boot 1.5.6.RELEASE
I am assuming you are familiar with creating a Spring Boot starter project either in your STS IDE or from the Spring Initializr site.

Salesforce 

I am assuming you have access to a Salesforce instance. If not, signup for a free developer edition. I further assume that you know how to create a connected app and write a simple Apex class with SOQL queries to query for standard or custom objects. This blog post cannot cover all the basics of Salesforce and the Apex programming language.

Steps to take on Salesforce side

You need to do two things on the salesforce side -

  • Create a new connected application or use an existing connected application.
  • Create a Apex class and expose it via the Salesforce REST API mechanism


Create a new connected application

  • Create a connected app and ensure that you enable OAuth. Details here.

Use an existing connected application 

If you already have a connected app and have not enabled OAuth, then follow these steps
  • Click on the connected app name.


Connected Apps













  • On the page showing your app details, look at the OAuth Policies section. For getting this example to work, ensure that the IP Relaxation has a value of "Relax IP restrictions".
    What this means is that any host can connect with your app. Later on, you can fine tune access based on a set of IP addresses. (Initially, I was unable to connect to the REST API and received error messages when I called the API using CURL from the command line. Finally, I figured out that I needed to set this feature to relax the IP addresses which can call the Salesforce API.)
  • Now go the Setup page by clicking the link on the top right in the header of the page (next to your name. For the new Lightning Experience UI, this is in a drop down menu.). 
  • Using the left search menu look for "Apps"
  • Click on the Apps option under the Build -> Create menu on the left side.
  • You should see your existing connected app listed in the Connected Apps section at the bottom of the page on the right side.
  • Once again, click on the name of your app to see the details page of your app
  • Click on the Edit button to edit your application settings
  • On the edit page, enable OAuth and enter data to make your app's OAuth settings look similar to this screen shot.
OAuth settings












  • When you enable OAuth and click Save you should see the API (Enable OAuth Settings) section populated with important data which is required for connecting to your Salesforce REST API from an external REST client.
  • Copy the Consumer Key and store it safely. This will be the client_id will be used in the API client code for authentication
  • Click on the Click to reveal link next to the Consumer Secret to view the value and store it safely. This will be the client_secret which will be used in the API client code for authentication

Writing a Apex class and exposing it via REST

Its quite easy to write an Apex class and expose it via REST. The following example code returns just 2 Account objects when invoked via the REST url. You should refer the official Salesforce documentation for details.

Create a new Apex class, named anything you like, as follows using the Dev console.

 @RestResource(urlMapping = '/Account/*')  
 global with sharing class MyRestResource {  
   @HttpGet  
   global static List<Account> getAccounts() {  
     List<Account> result = [SELECT Id, Name, Phone, Website FROM Account LIMIT 2];  
     return result;  
   }  
 }  


Now work is done from Salesforce side. If you are familiar with Curl then you can try calling this URL and test the response. Note that you will have to authenticate first to obtain a OAuth token to access the REST url.

Setting up the Spring Boot RestTemplate code

The following code is brief and meant to just shows how to authenticate and then access the REST url.  I assume that you are familiar with creating a Spring Boot starter app.

Configure the Spring RestTemplate

Create a package called config , e.g. com.example.config in your project and copy paste the following class. This will set some defaults like timeout for attributes of the RestTemplate. For more details refer the Spring docs at this link.


import org.springframework.context.annotation.Bean;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;

@Component
public class RestTemplateConfig {
 
 @Bean
 public ClientHttpRequestFactory clientHttpRequestFactory() {
  int timeout = 5000;
  HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
  clientHttpRequestFactory.setConnectTimeout(timeout);
  clientHttpRequestFactory.setConnectionRequestTimeout(timeout);
  clientHttpRequestFactory.setReadTimeout(timeout);
  return clientHttpRequestFactory;
 }
}

Code that authenticates and calls the REST api

The following code will first authenticate with the Salesforce OAuth service and then call the REST url.


import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.salesforce.bigobjects.config.RestTemplateConfig;

@RestController
public class RestTemplateRequestToSalesforce {

 private static final Logger LOG = LoggerFactory.getLogger(RestTemplateRequestToSalesforce.class);

 // Inject the Rest template configuration
 @Autowired
 RestTemplateConfig restConfig;

 /**
  * Simple Rest end point in this app to demonstrate authenticating and then calling the Salesforce REST url
  * 
  * @return
  */
 @GetMapping("/accounts")
 public String callRestUrl() {

  // First define the OAuth2 token URL as follows by replacing YOUR_INSTANCE
  // with the actual instance that you have your org on
  String oauthUrl = "https://YOUR_INSTANCE.salesforce.com/services/oauth2/token";

  // Create a multi value map to put necessary attributes
  // for the authentication request
  MultiValueMap<String, String> mvMap = new LinkedMultiValueMap<>();
  mvMap.add("grant_type", "password");
  mvMap.add("client_id", "Your Client Id");
  mvMap.add("client_secret", "Your Client Secret");
  mvMap.add("username", "Your username");
  mvMap.add("password", "Your password");

  // Create an instance of the RestTemplate
  RestTemplate restTemplate = new RestTemplate(restConfig.clientHttpRequestFactory());

  // Send the REST request to get authenticated and receive an OAuth token
  Map<String, String> token = (Map<String, String>) restTemplate.postForObject(oauthUrl, mvMap, Map.class);
  LOG.info("--------------------------------------------");
  LOG.info("Access Token  :: " + token.get("access_token"));
  LOG.info("Instance Url  :: " + token.get("instance_url"));
  LOG.info("Id  :: " + token.get("id"));
  LOG.info("Token_Type  :: " + token.get("token_type"));
  LOG.info("Signature  :: " + token.get("signature"));
  LOG.info("--------------------------------------------");

  // The oauth token is now required for all further calls to the REST resources
  String oauthToken = token.get("access_token");

  // The REST url of your Salesforce Apex class will be of the form
  String restUrl = "https://YOUR_ISTANCE.salesforce.com/services/apexrest/Account";

  // Create Http headers and add the oauth token to them
  HttpHeaders restHeaders = new HttpHeaders();
  restHeaders.setContentType(MediaType.APPLICATION_JSON);
  restHeaders.add("X-PrettyPrint", "1");
  restHeaders.add("Authorization", "OAuth " + oauthToken);

  // Create a Multi value map in case there are query params. In this example
  // there are none so just an empty map is okay
  MultiValueMap<String, String> mv2Map = new LinkedMultiValueMap<>();

  // Following example code is using the RestTemplate exchange(..) method for making a GET request
  // Other methods like getForEntity() or getForObject() can also be used.
  HttpEntity<?> restRequest = new HttpEntity<>(mv2Map, restHeaders);
  RestTemplate getRestTemplate = new RestTemplate(restConfig.clientHttpRequestFactory());
  // Make a request and read the response string
  ResponseEntity<String> responseStr = getRestTemplate.exchange(restUrl, HttpMethod.GET, restRequest,
    String.class);

  // Return just the body of the response. You can examine the headers, etc if you wish
  HttpStatus responseStatus = responseStr.getStatusCode();
  HttpHeaders responseHeaders = responseStr.getHeaders();
  String responseBody = responseStr.getBody();
  LOG.info("REST API response:" + responseBody);
  return responseBody;
 }
}



Summary

The code is quite straightforward. Authenticate and obtain an OAuth token. Use this token is subsequent requests.

Monday, October 23, 2017

Sending form data as a custom object to a Spring MVC Controller


Form Data and Spring MVC Controllers

In a Spring MVC application, sending form data to the controller is quite well known and trivial. Typically all data gets sent as a bunch of key=value pairs. Each key is a request param which can be captured in the Controller using the @RequestParam("key") String key construct in the method signature.

If the number of fields are less, then you can use the request param construct to capture each form field, but if there are several form fields, then using this approach can create a unwieldy method signature and create room for error.

There are several ways to collect form data but in this post, I am going to address one specific use case.

Motivation for this post

Recently, someone at work asked me how to send data so that it was received by the Spring controller as a custom object/Pojo. I suggested using javascript to massage and format the data as desired and then send it.

Now using jquery forms on the browser side you can send data in any format after converting it to a JSON string.

For some business reasons, javascript was not an option. The HTML form had to be submitted as is using traditional http post method.

The purpose of this short blog post is to demonstrate how to send data from the browser without the help of javascript or any jquery plugins. This is typically useful when you have checkboxes and radio buttons in the UI and there is a relation between them.

Example

I have created an example UI which shows the kind of form that was to be submitted and then the controller code which processes the http post of this form.



As you can see, this form shows a list of car makes and their colors. The idea is that the user will check a checkbox for a car make and then select a color using the radio buttons.

Note that this form is rendered on the server side by reading the car makes and colors and then sent as a HTML page to the browser.

The HTML generated for this form is like this

 <form name="customObjectForm" id="customObjectForm" method="post" action="/submit">  
   <table class="table table-striped table-condensed table-bordered">  
     <thead>  
       <tr>  
         <th>Vehicle</th>  
         <th>Select</th>  
         <th>Color</th>  
       </tr>  
     </thead>  
     <tbody>  
       <tr>  
         <td>Toyota Camry</td>  
         <td><input type="checkbox" name="carModel" value="Camry" /></td>  
         <td>  
           <input type="radio" name="colors[Camry]" value="RED" /> RED &nbsp;  
           <input type="radio" name="colors[Camry]" value="YELLOW" /> YELLOW&nbsp;  
           <input type="radio" name="colors[Camry]" value="GREEN" /> GREEN&nbsp;  
         </td>  
       </tr>  
       <tr>  
         <td>Honda Civic</td>  
         <td><input type="checkbox" name="carModel" value="Honda" /></td>  
         <td>  
           <input type="radio" name="colors[Honda]" value="BLUE" /> BLUE&nbsp;  
           <input type="radio" name="colors[Honda]" value="BLACK" /> BLACK&nbsp;  
           <input type="radio" name="colors[Honda]" value="GREEN" /> GREEN&nbsp;  
         </td>  
       </tr>  
     </tbody>  
     <tfoot>  
       <tr><td colspan="3"><input type="Submit" name="submit" class="btn btn-primary" /></td></tr>  
     </tfoot>  
   </table>  
 </form>  

Domain model

If you examine the HTML, you will notice that we can infer a Key Value pair type relationship between the car make and the color options. To relate the car make to the colors, the name of the radio buttons is named like an associative array with the car make as the value of the colors variable. 

The car make checkboxes can be represented as a List in the domain model. If a user checks a checkbox then that checkbox value is submitted by the form, otherwise it is not.

Next, the row showing color options must be related to the car make in the domain model. To make that happen, the radio button selection can be submitted as a Map in the domain model.

So the car model can be a List<String> carMakes and the car colors can be a Map<String, String> colors where the key is the car make and the value is the actual selected color.

There can be a better domain model created and the HTML can be structured accordingly, but this is a quick example to show how Spring can convert browser submitted values in ready to use custom objects that you define.

Here is the CarMakeColorModel domain object / POJO.

package com.example.formobjects.model;

import java.util.List;
import java.util.Map;

public class CarMakeColorModel {

 // for the checkboxes for selecting the car makes
 private List<String> carMakes;

 // for the radio buttons to select the car color
 private Map<String, String> colors;

 public CarMakeColorModel() {
  // default constructor
  super();
 }

 public CarMakeColorModel(List<String> carMakes, Map<String, String> colors) {
  super();
  this.carMakes = carMakes;
  this.colors = colors;
 }

 public List<String> getCarMakes() {
  return carMakes;
 }

 public void setCarMakes(List<String> carMakes) {
  this.carMakes = carMakes;
 }

 public Map<String, String> getColors() {
  return colors;
 }

 public void setColors(Map<String, String> colors) {
  this.colors = colors;
 }

}


On the Controller side, use the @ModelAttribute annotation to make Spring collect all the form submitted values and populate the CarMakeColorModel pojo.

And here is the Spring Controller snippet which processes this HTML form.


package com.example.formobjects.controllers;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.example.formobjects.model.CarMakeColorModel;

/**
 * Controller to handle the form submission
 * 
 * @author <a href="mailto:sunitkatkar@gmail.com">Sunit Katkar</a>
 * @version 1.0
 * @since Oct 2017
 */
@Controller
public class FormCustomObjectController {

 @RequestMapping(value = "/", method = RequestMethod.GET)
 public String index(ModelMap modelMap) {
  return "index";
 }

 @RequestMapping(value = "/submit", method = RequestMethod.POST)
 public String submit(HttpServletRequest request, ModelMap modelMap,
   @ModelAttribute CarMakeColorModel carMakeColorModel) {

  List<String> carMakes = carMakeColorModel.getCarMakes();
  Map<String, String> carColors = carMakeColorModel.getColors();
  for (String carModel : carMakes) {
   String color = carColors.get(carModel);
   System.out.println("Car make:" + carModel + " Car color:" + color);
  }
  return "index";
 }

}


What I have shown is a known way of processing forms completely on the server side without aid of javascript. Though many of you know this technique, I am sure there are some out there, like my colleague, who are not aware of this; hence this post.

That's all there is to it. Happy coding :)