Tuesday, June 30, 2015

Parsing JSON in Apex

This article will explain how to parse JSON content and deserialize  JSON into Apex objects.

Use the JSONParser methods to parse a response that's returned from a call to an external service that is in JSON format, such as a JSON-encoded response of a Web service call out.

There are 2 ways you can parse JSON in apex. We will cover both option and their benefits.


1. Parsing JSON by inspecting each JSONToken present in JSON


Generally this method is useful for grabbing specific pieces of data from JSON. The System.JSONToken is an enumerator that provides values such as FIELD_NAME, START_OBJECT, END_OBJECT and others that inform you of the type of token currently being parsed.
Below is sample JSON (JSON response from callout to Box.com) which we will be using here for parsing.

{  
   "type":"session",
   "id":"d1425e031062455f909740bb770b95a7",
   "document":{  
      "type":"document",
      "id":"ab0dc2d377524f44a98fd1476343637e",
      "status":"processing",
      "name":"",
      "created_at":"2015-06-19T08:35:09Z"
   },
   "expires_at":"2015-06-19T09:35:10.020Z",
   "urls":{  
      "view":"https://view-api.box.com/1/sessions/d1425e031062455f909740bb770b95a7/view",
      "assets":"https://view-api.box.com/1/sessions/d1425e031062455f909740bb770b95a7/assets/",
      "realtime":"https://view-api.box.com/sse/d1425e031062455f909740bb770b95a7"
   }
}

Now suppose if we have to fetch the session id from JSON, then we will be using below code:

HTTPResponse res=sendHttpRequest(req);
String response=res.getBody();
String SessionId='';
JSONParser  parser = JSON.createParser(Response);
while (parser.nextToken() != null) {
if ((parser.getCurrentToken() == JSONToken.FIELD_NAME)){
String fieldName = parser.getText();
parser.nextToken();
String fieldValue=parser.getText();
if(fieldName == 'type' && fieldValue=='session') {
parser.nextToken();
if(parser.getText()=='id'){
parser.nextToken();
SessionId= parser.getText();
break;
}
}
}
}

The code above executes a while loop that walks through the entire JSON string using the parser.nextToken() method and parses simple field text values such as id or session using the parser.getText() method.

If we need only specific information like session id, then we will check token value as id after type and session token. After getting the session id, we are breaking the loop so that we are not getting any other token with value id in JSON.

Points to remember while using this approch:
  • If you want specific information from JSON, then use this approach instead of storing all JSON information in apex objects.
  • Developer has to check different tokens in order to get required value from JSON.


2. Parsing JSON by deserializing It into Object


In this approch, we are going create a apex class and deserialize the JSON to store information in apex class variable. This approach is very simple but the only thing is that you need to defined Apex classes mapped to each of the element/entity represented in the JSON string.

You can refer below URL in order to generate apex class structure for JSON.

http://json2apex.herokuapp.com/


Paste your JSON in this tool and it will generate required apex class for deserializing the JSON. Below is class generate for above sample JSON response:




You can define getter setter methods for variables if you want to display on VF page like:
public String type {get;set;}
public String type {get;set;}

If we are using inner class to store values, then we can remove the parse method and testmethod from above generated apex code. Below is simplified version of class which we can be used to deserialize JSON:

public class JSON2Apex {
public class Document {
public String type;
public String id;
public String status;
public String name;
public String created_at;
}
public class Urls {
public String view;
public String assets;
public String realtime;
}
public String type;
public String id;
public Document document;
public String expires_at;
public Urls urls;
}

Now we have apex class required to deserialize the JSON String. We can deserialize the JSON with single line of code in apex mentioned below:


HTTPResponse res=sendHttpRequest(req);

String response=res.getBody();
JSON2Apex   JSONDetails=(JSON2Apex) System.JSON.deserialize(response, JSON2Apex.class);

Now you will have all information from JSON into apex class variables.


Points to remember while using this approach:
  • It is not required that you have to create variables for all elements/entity in apex class. In our example, if you don't want fetch urls information from JSON, then you can remove URLs public class. from JSON2Apex class. Also you can remove other variables like type, created_at etc from JSON2Apex class if not required in your apex class.
  • For multi-level nested JSON, you are limited by the depth of inner class as you can only have one level of inner class in apex. If you need to parse deeper nested JSON, then use parsing through tokens.



Sunday, June 21, 2015

Box and Salesforce Integration

In this blog, I am going to explain how to integrate Box.com and Salesforce using Apex and VF in order to upload document to Box and to view files present in Box in VF page.

First of all, Create a Box Application


Create Box content application which will help us to upload files directly from Salesforce to Box.com.  After creating app, copy client_id and client_secret values and specify your VF page URL as redirect_uri in Oauth 2 parameters section.


Now create another application and select Box view application. This will help us to view files in VF page. View API allow to convert files in HTML format for easy display in web pages. Copy view API Key from General information section.


Now Create a custom setting in Salesforce to store client_id,client_secret, access token, refresh token and View API key.



Now Create Remote site setting in order to do call out to Box.com.


Now create a VF page "boxAuthPage" and apex class "boxAuthPageController". Code is provided in end of this blog. Please scroll down to copy code and paste in your VF and apex class.

Snapshot of VF page:

Store client_id, client_secret, view api key in custom setting record. While creating custom setting record, I have specified "Box_sunil02kumar' as name for custom setting. If you want to use other name, then replace "Box_sunil02kumar' in apex class with your custom setting name.

Open VF page and click on Authorize Box button, system will redirect you to login page where you need to enter you box login credential and then a click grant access to box button.

All folder present in box will be listed in Folders drop down. When you select any particular folder, all files present in that folder will appear in page block table. When you click on "View" link, file will open on right side of page.

If you have box account, then use below url to test the functionality. Create folders in your box account and upload pdf and doc files in it. If you upload files with already existing file name in Box folder, then you will get error.

https://skforce-developer-edition.ap1.force.com/skforce__boxauthpage

I have built this page for demo. So every time you refresh this page, you need to again authorize it by clicking on Authorize box button. Actually I am not storing access token or refresh token or any user credentials and also scope of these variables are same as that of VF page. Also client id, client secret and access tokens are not displayed in demo page but if you follow all steps mentioned above including custom setting and remote site setting, then you will get complete UI.

Important information which will help you to understand apex class:
  • Uploading data into box.com uses content type as multipart/form-data.
  • You can not send a file to server which is expecting a binary. So you need to encode the base64 in binary supported format.
  • In order to view document, first you need to send request to get temporary download URL by sending file id to Box.com. Temporary download URL is returned in response Location header. This URL can be used to download file.
  • Once you get temporary download URL, sent request to BOX.com to get temporary document id. In HTTPRequest, you need to pass temporary download URL in body.
  • Now this document id which you get in response can be used to generate session id for file which will be used to view file in iframe in VF page. When you do call out to get session id, pass temporary document id in request body.
  • If file is processed by Box.com and is ready to view, then in response you will get session id. If your request is accepted but file is not yet converted to HTML format then in response header, you will time duration after which file will be ready. This information is present in 'retry' header in response.
  • Once you get file session id from Box.com, then you use it view file in iframe in your VF page by using  URL: https://view-api.box.com/1/sessions/'+fileSessionId+'/view


Notes:
  • You can upload any type of file to box folder.
  • Before uploading any file, please select folder in which you want to upload file.
  • As per my knowledge, View API doesn't support jpg and png images. 
  • You can easily view any pdf or word file from Box in SFDC using view api.
  • You can also specify download URL. Please refer Box content view API for this.
  • In apex, code is specified to get file download URL in FindFileDownloadUrl method in apex class.
This blog will help you to basic understanding of how to achieve integration between Box and SFDC by using apex code. After going through this code, you can easily modify the code as per your requirements.

Code for VF and apex class: