Max Krebs

REST APIs with Salesforce

This is going to be diverting a little bit from the normal area of programming that I cover. At my joby-job, we do most of our work in developing on the Salesforce platform. Normally, Salesforce is used for really boring CRM and marketing, but our clients come to us with problems and we solve them. Tangentially, I’ve been thinking a lot about my relationship with Salesforce as a platform, and I think that there are some ways that the incredible restrictions Salesforce places on its developers has been making me better at writing good software, but more on that soon I think.

For right now, I wanted to go into detail about a particular type of solution that I’ve been working on in the last couple of months, and that is writing REST APIs for Salesforce.

The use case is this: a client has an existing Salesforce database that they are using for pretty straightforward contact management, but they want to integrate data from an external data source. The primary example I’ve been working with lately is that a client has a form on their website that they want to feed into their Salesforce database, but with some domain specific logic involved. there are ways to send data into Salesforce from elsewhere on the web, but I find that they are mostly too restrictive and don’t let you apply custom logic in an intuitive and scalable way.

Thus enters the Apex Rest framework. Previously, I’ve made most of my REST APIs in Rails, and I would still prefer to work in that framework and language (although I am becoming increasingly interested in both Sinatra and Elixir). However, after getting over the initial learning curve, I can bust out a pretty solid Apex REST API for sending data into and out of Salesforce.

The first step to setting up an Apex class for access via REST is to create a global class with sharing, and the @RESTRESOURCE class annotation.

@RestResource(urlMapping='/Project/*')
global with sharing class Project {

}

The urlMapping part of the class annotation denotes the, you guessed it, URL used to access the class.

That is all the class level setup that is required to register it for access through REST. There might be some other configuration needed to make your new REST API fully functional such as registering a connected app and setting up user profiles, but that is outside of the code and beyond the scope of this post.

The next step is defining methods to handle the various types of HTTP requests the API will be sent. This can be done by defining a method with the appropriate annotation that matches the request type. You can name the method however you like, but I find it helpful to stick with a convention, and since Apex is roughly based on Java, I find it helpful to stick with the Java servlet conventions of doGet, doPost etc.

@HttpPost
global static void doPost(String name, Date dueDate, String Description) {
  ...
}

If you are used to how Rails treats controller methods, the parameters in the function definition may stand out to you (they are extremely Java-y), but that is actually how you define what JSON payload you are expecting. For the method definition above, the expected JSON payload would be:

{
  "name": "projectName",
  "dueDate": "projectDueDate",
  "Description": "projectDescription"
}

Salesforce’s JSON parser takes the first depth level of the JSON payload and passes that into the parameters of the HTTP method. This is sufficient to handle most requirements, but things get a little hairier if you need to send nested JSON, but it is possible.

Take for example this payload:

{
  "name": "projectName",
  "dueDate": "projectDueDate",
  "description": "projectDescription",
  "developer" : {
    "firstName": "developerFirstName",
    "lastName": "developerLastName"
  }
}

If you try and send that payload to the above function, Salesforce is going to send you back a JSON parsing error before you even hit the class method. To address nested JSON, you have to include an Apex inner class to represent that nested object.

@HttpPost
global static void doPost(String name, Date dueDate, String Description, Developer developer) {
  ...
}

global class Developer {
  public String firstName {get;set;}
  public String lastName {get;set;}
}

You can then access the nested JSON data like any other object. Again, its fairly unintuitive, but it makes its own kind of weird sense once you get used to it.

After that, you can execute any other code in the method body that you need to and whatever the method returns will be sent as the response to the HTTP request. You can do this explicitly by return 'Successfully Created Project' or by setting the response body in the Apex RestContext method.

String responsebody = '{' +
                      '"id" : "'+project.Id+'",' +
                      '"success" : true,' +
                      '"errors" : [ ]' +
                       '}';
RestContext.response.addHeader('Content-Type', 'application/json');
RestContext.response.responseBody = Blob.valueOf(responsebody);

This will send back whatever JSON you define. I like to send back the Id of any record created in the course of the method because that follows the conventions of the other Salesforce APIs.

That is all there is to it. There is some weird annotation syntax and the JSON parser is a little finicky, but there is power in being able to define your own way to send data in and out of a Salesforce database.