Uploading a document to Salesforce using REST API

Adi
5 min readFeb 8, 2016

--

For the past few days , I have been trying to figure out how to upload a file to Salesforce from Java using the REST API . At first it seemed tough , but once you understand the MIME and MultiPart Messages , it becomes easy. Without further ado,lets see how to do it .

What is a MultiPart Message ?

A MultiPart Message is a message which has several parts separated by a specific boundary. Each part has its own header and body. The boundary string are the texts that are prefixed and postfixed by “- -” . Below is how a typical message looks like :

MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=frontier

This is a message with multiple parts in MIME format.
--frontier
Content-Type: text/plain

This is the body of the message.
--frontier
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64

PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg
Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==
--frontier--
Source : Wikipedia

As you can see above , “frontier” is the boundary that separates the parts of the message. Each part has its own Content Type header and body.

How to use the Document Rest API ?

The Document Rest API provides a easy way to insert or upload documents to Salesforce. These documents can be images or text or pdfs or any type. The request that is sent must be a multipart message having 2 parts. The first part is a non-binary part which provides information about the file being uploaded and also the location/folder where the file is stored. The second part is a binary part which contains the data of the file being uploaded. So summarizing below

Rest URL      : <Instance URL>services/data/v23.0/sobjects/Document/Method               : HTTP POSTRequest Message Type : MultiPart/Form-Data Parts of Message     : 2 Parts , 1 Binary and 1 Non-Binary 

What does the message to Salesforce look like ?

The multipart message is very similar to the one shown earlier. Taking the example from Salesforce docs , below is the typical message that is sent .

 — boundary_string
Content-Disposition: form-data; name=”entity_document”;
Content-Type: application/json
{
“Description” : “Marketing brochure for Q1 2011”,
“Keywords” : “marketing,sales,update”,
“FolderId” : “005D0000001GiU7”,
“Name” : “Marketing Brochure Q1”,
“Type” : “pdf”
}
— boundary_string
Content-Type: application/pdf
Content-Disposition: form-data; name=”Body”; filename=”2011Q1MktgBrochure.pdf”
Binary data goes here. — boundary_string —

As you can see there are 2 parts : 1 part is the entity_document which provides details of the document to be created and the 2nd part is the binary data that is the actual file to be uploaded and this part gets populated into the Body field of the Document Object.

Below are the mandatory fields that Salesforce requires in order to create the Document Object record. These need to be present in the multipart message .

Document Object : //Part 1 : Non-Binary . Name = 'entity_dcoument'Name       : Name for the document/file being uploaded Folder Id  : Folder where the file will be stored.//Part 2 : Binary. Name = 'Body'Body       : Binary content of the file . 

How does the destination(Server) read the Multipart Message ?

All details that are required for the Server to process are present in the Multipart Message itself. As such there is no particular standard that is followed. Currently , implementation of parsing a multipart message varies from 1 system to another i.e. Salesforce might have a particular implementation logic . Some other like Google may have another. Simply put , one has to read the required API docs to understand what is it that the destination requires in order for the request to be successful.

A very simple processing logic would be as follows :

  1. Using the boundary string that is provided , one can get the individual parts.
  2. Each part now has its own headers that will help one to parse it accordingly.

This is the very basic approach , although there might be more complex ones , but for this blog , the basic approach seems to work.

What are the steps that the Java code should do ?

Now that we know what a Multipart message is and what Salesforce expects from the request that is being sent , we can proceed to the list of steps that we need to do in the Java application .

Steps involved : 1. Identify the Document Rest URL based on your environment. 2. Ensure you have required parameters specifically Auth Token,Folder Id,Name and Body. At the minimum these are required . 3. Create a Multipart Message . Set to Strict Mode as this ensures that the headers for each part are set accordingly. 4. Set the headers for the Post Request . For Content-Type , also provide the Boundary String that is being used . 5. Send the Post Request and parse the response received accordingly.

Code Walkthrough

Putting all the information that I learnt in the previous sections and also from the Salesforce docs , I was able to come up with a working java code that is able to upload a file and receive a successful response from Salesforce.

The code is present in Github and I will highlight the important parts of it below.

  1. config.properties : This file contains the required parameters like Rest URL ,Auth Token and Folder Id .
/*The Document Rest URL
* Provide your instance or sandbox url accordingly.
*documentRestURL = https://<Sandbox/Instance>.salesforce.com/services/data/v<Version>/sobjects/Document/
*/
documentRestURL = https://ap1.salesforce.com/services/data/v34.0/sobjects/Document/
/*
* authToken : Provide the Session Id
*/
authToken = <sessionId>
/*
*folderId : Provide the Folder Id where to upload the document
*/
folderId = <folderId>

2. Building the Post Request Body : PostRequestBuilder class takes care of building the request body along with the required headers. Following Code Snippets show the important methods present in the class.

Method : buildRequestBody

/*
* Function : buildRequestBody
* Description : This prepares the Body for the HttpPost
* @returns : HttpEntity
*/
private HttpEntity buildRequestBody()
{
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
//Set the Boundary String
builder.setBoundary(boundary);
//Set the Mode — This will put the Content-Disposition and Content-Type headers in the request Body
builder.setMode(HttpMultipartMode.STRICT);
//Add the Non-Binary Part i.e. Details of the Document being uploaded
builder.addTextBody(“entity_document”,docDetails.prepareJSON(),ContentType.APPLICATION_JSON);
//Add the Binary Part i.e. File Contents
File inpFile = new File(filetoUpload);
FileBody fb;
fb = new FileBody(inpFile,ContentType.create(fileType));
builder.addPart(“Body”, fb);
return builder.build();

}

Essentially the above method does the below steps :

  • Set the Mode of the Multipart Message to Strict : This is required , otherwise the parts of the message will not have required content headers resulting in Salesforce not being able to parse the message.
  • Set the boundary String to be used. I have used boundary<CurrentTimeMillisec> . This will have to be set in the Post Request header in Content-Type.
  • Add the Binary and Non-Binary Parts.

Method : preparePostRequest

/*
* Function : preparePostRequest
* Description : This prepares the HttpPost Request
* @returns : HttpPost
*/
public HttpPost preparePostRequest()
{
HttpPost hpost = new HttpPost(Configs.getDocumentRestURL());
// Set the Headers
// Set Authorization
hpost.addHeader(“Authorization”, “Bearer “ + Configs.getAuthToken());
// Set the Content Type
hpost.addHeader(“Content-Type”,”multipart/form-data;boundary=” + boundary);
//Set the Request Body
hpost.setEntity(buildRequestBody());
return hpost;

}

Note : In the Content-Type header , also provide the boundary string that you used. That way Salesforce is able to process the multipart message and I am able to get successful response.

3. pom.xml : The java project was built using Maven to take care of the dependencies. More specifically below are the external libraries that I used.

  • HttpClient 4.5
  • Commons-Logging 1.2
  • Google GSON 1.7.1
  • HttpMime 4.5.1
  • Commons IO 2.4

Source Code : Available here

--

--