function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Board salesforceBoard salesforce 

Creation of folder in box from salesforce

public void CreateFolder(){
//BoxFolder folder = new BoxFolder('bbwh00nt6dylw1w8y1z7p0dnm4zd2m8n', '"Parent": {"id":"0"}');
HttpRequest request=new HttpRequest();
request.setendpoint('https://api.box.com/2.0/folders'); 
request.setmethod('POST');
request.setHeader('Authorization','Bearer ' + AccessToken);
string body= '{"name":"test", "parent": {"id": "0"}}';
request.setBody(body);
Http p=new Http();
HttpResponse response=p.send(request);
jsonFolderResponse=response.getBody();
System.debug('jsonFolderResponse'+jsonFolderResponse);
}

Hi am getting the following error can any one help out.

16:56:12:643 USER_DEBUG [49]|DEBUG|jsonFolderResponse{"type":"error","status":400,"code":"bad_request","context_info":{"errors":[{"reason":"invalid_parameter","name":"entity-body","message":"Invalid value '{\"name\":\"Test\",\"Parent\":\" {\"id\":\"0\"}\"}'. Entity body should be a correctly nested resource attribute name\/value pair"}]},"help_url":"http:\/\/developers.box.com\/docs\/#errors","message":"Bad Request","request_id":"62736846156efda548b4e5"}

Thanks,
Ram
pconpcon
Your request works perfectly for me.  I make the same call, and I get a 200 response code back, and the folder gets created.

If you try to run this with cURL, does it succeed as expected?
Board salesforceBoard salesforce
HI Pcon ,

Thanks for the Response,
I have tried this above code in apex i got the above error .can you please  help me out in creation of folder in box from salesforce with sample code that you have succeeded.

Thanks,
Ram 
pconpcon
I run the exact same code that you have and it works without an issue.
 
String authToken = 'XXXXXX';

String body= '{"name": "testForBoards", "parent": {"id": "0"}}';

HttpRequest request=new HttpRequest();
request.setEndpoint('https://api.box.com/2.0/folders'); 
request.setMethod('POST');
request.setHeader('Authorization', 'Bearer ' + authToken);
request.setBody(body);

Http p = new Http();
HttpResponse response = p.send(request);
System.debug(System.LoggingLevel.ERROR, response.getStatusCode());
System.debug(System.LoggingLevel.ERROR, response.getStatus());
System.debug(System.LoggingLevel.ERROR, response.getBody());

User-added image
 
09:53:43:440 USER_DEBUG [13]|ERROR|201
09:53:43:440 USER_DEBUG [14]|ERROR|Created
09:53:43:440 USER_DEBUG [15]|ERROR|{"type":"folder","id":"7183551965","sequence_id":"0","etag":"0","name":"testForBoards","created_at":"2016-03-28T06:53:43-07:00","modified_at":"2016-03-28T06:53:43-07:00","description":"","size":0,"path_collection":{"total_count":1,"entries":[{"type":"folder","id":"0","sequence_id":null,"etag":null,"name":"All Files"}]},"created_by":{"type":"user","id":"16246742","name":"Patrick Connelly","login":"patrick@███████.com"},"modified_by":{"type":"user","id":"16246742","name":"Patrick Connelly","login":"patrick@███████.com"},"trashed_at":null,"purged_at":null,"content_created_at":"2016-03-28T06:53:43-07:00","content_modified_at":"2016-03-28T06:53:43-07:00","owned_by":{"type":"user","id":"16246742","name":"Patrick Connelly","login":"patrick@███████.com"},"shared_link":null,"folder_upload_email":null,"parent":{"type":"folder","id":"0","sequence_id":null,"etag":null,"name":"All Files"},"item_status":"active","item_collection":{"total_count":0,"entries":[],"offset":0,"limit":100,"order":[{"by":"type","direction":"ASC"},{"by":"name","direction":"ASC"}]}}

Based on the error message you have in your inital post it looks like it may be that your access token has expired.  You can try to add the following to your code to see all the resulting headers to see if there is more information there.
 
for (String key : response.getHeaderKeys()) {
    if (key != null) {
    	System.debug(System.LoggingLevel.ERROR, key + '=>' + response.getHeader(key));
    }
}
Board salesforceBoard salesforce
HI pcon ,
Awesome that works fine.
here i have an issue which try to integrate with trigger ,class with callout method ,i am unable to hold the code until or unless i click grant access now i want to skip grant access step directly in backend  to genrate code and  follow on with access token..can you help me out 
pconpcon
Just to clarify, you're trying to do the oauth flow without the grant access step?
Board salesforceBoard salesforce
Thanks for the Quick respond pcon
Yes absolutely you are right can you please help out
pconpcon
The only way to do this is using xauth [1] and Box doesn't seem to support xauth.  If your running this in a trigger, why do you need to have this as a headless auth?  You can store the auth token somewhere (like a custom setting) and generate it externally.  You can do the oauth flow with cURL and get the access_token that way.

[1] http://stackoverflow.com/questions/3324238/what-is-the-difference-among-basicauth-oauth-and-xauth
Board salesforceBoard salesforce
Thanks pcon am pretty new to cUrl i have to workaround that can share the related links that helps much
is there any other way to do?any related code to store authcode and token generation using cURL?that helps me a lot
pconpcon
The generation of the token is pretty easy [1] you'll just want to grab the "access_token" from the response JSON.  As for storing and retreiving data from custom settings, you can read over these [2][3][4].  You'll most likely want to use a "List" type setting and give it a name like "default" and then do your MyCustomSetting__c.getValues('default').

Just a side note about custom settings, you will have to create them inside your test classes.  They live in a kind of half place between data and metadata and are not accessable via tests (without seeAllData) unless you create them first.

[1] https://labs.hybris.com/2012/06/18/trying-out-oauth2-via-curl/
[2] https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_custom_settings.htm
[3] https://help.salesforce.com/apex/HTViewHelpDoc?id=cs_accessing.htm&language=en
[4] https://help.salesforce.com/HTViewHelpDoc?id=cs_limits.htm&language=en_US
Board salesforceBoard salesforce
Hey pcon,

Curl is the thing in command prompt,i want it using apex and api based is their any other way to aprroach this ? 
pconpcon
You could do the oauth flow via anonymous apex and store that, but it would still require you auth the app the first time
Board salesforceBoard salesforce
yes pcon it curl doesnt works for my requirement ,is their any alternative ?
pconpcon
You can create a Visualforce page that handles your oauth flow.  Then stores the access token in the custom setting.  Then make that VF page only available to administrators.  This would allow you to do the flow, approve the application and then have the access token available.
Board salesforceBoard salesforce
Pcon through vf i am done but i want to acheive through trigger as when ever account is created then box folder should created as account name 
pconpcon
If you want to do this 100% within Salesforce your flow would be like

Setup
  1. Call Visualforce page the redirects for oAuth login
  2. Approve application
  3. Return from oAuth flow to Visualforce page
  4. Store access_token from payload into custom setting
Account trigger (on insert)
  1. Pull access_token from custom setting
  2. If null, exit
  3. Make @future callout to box endpoint to create folder with access_token
Board salesforceBoard salesforce
Class to perform Callout
============================
public class BoxController  {
    
    
    public static  string clientid;
    public static  string  clientsecret;
    public static string redirecturi;
    public static string code;
    public  static   string jsonresponse;
    public  static string accessToken;
    public static string ViewAPI_Key;
    public  static string RefreshToken;
    public  static  string  jsonFolderResponse;
    public  static string  jsonFolderResponse1;
    public  static string jsonItemsResponse;
    public  static string folderId;
    public static String FileViewUrl;
    public static String securitycode;
    public static string box_login;
    public integer i=0;
    public BoxController()
    {
        //redirecturi='https://na30.salesforce.com/apex/boxresponse2';
        
        /* clientid=BoxCCredentials__c.getValues('CredentialsBox').Client_Id__c;  
clientsecret=BoxCCredentials__c.getValues('CredentialsBox').Client_Secret__c;
ViewAPI_Key=BoxCCredentials__c.getValues('CredentialsBox').View_API_Key__c;
AccessToken=BoxCCredentials__c.getValues('CredentialsBox').Access_Token__c;
RefreshToken=BoxCCredentials__c.getValues('CredentialsBox').Refresh_Token__c;
system.debug('Client_Id__c'+clientid);
system.debug('clientsecret'+clientsecret);
system.debug('clientsecret'+ViewAPI_Key);
system.debug('clientsecret'+AccessToken);*/
        
    }
    @future(callout=true)
    public static void  boxAuthentication(string aid)
    {
        try
        {
           
        String endpointUrl1='https://app.box.com/api/oauth2/authorize?response_type=code&client_id='+clientid+'&state=symcsk02&box_login=boxpocintegration@gmail.com';
        redirecturi='https://na30.salesforce.com/boxresponse2';
        code=ApexPages.currentpage().getparameters().get('code');// Attempt to dereference null object at  commented line in boxcontroller class
        securitycode=ApexPages.currentPage().getparameters().get('state');
        //  
        clientid=BoxCCredentials__c.getValues('CredentialsBox').Client_Id__c;  
        clientsecret=BoxCCredentials__c.getValues('CredentialsBox').Client_Secret__c;
        ViewAPI_Key=BoxCCredentials__c.getValues('CredentialsBox').View_API_Key__c;
        AccessToken=BoxCCredentials__c.getValues('CredentialsBox').Access_Token__c;
        RefreshToken=BoxCCredentials__c.getValues('CredentialsBox').Refresh_Token__c;
        system.debug('Client_Id__c'+clientid);
        system.debug('clientsecret'+clientsecret);
        system.debug('clientsecret'+ViewAPI_Key);
        system.debug('clientsecret'+AccessToken);
        
        HttpRequest request=new HttpRequest();
        request.setendpoint('https://api.box.com/oauth2/token'); 
        request.setmethod('POST');
        string body='grant_type=authorization_code&';
          body=body+'box_login'+box_login;  
        body=body+'code='+code;
        body=body+'&client_id='+clientid;
        body=body+'&client_secret='+clientsecret;
        request.setBody(body);
        Http p=new Http();
        HttpResponse response=p.send(request);
        jsonresponse=response.getBody();
        fromJSON js=(fromJSON)JSON.deserialize(jsonresponse,fromJSON.class);
        accessToken=js.access_token;
        system.debug('accessToken' +accessToken);
        
        system.debug('code is '+code);
        
        HttpRequest request1=new HttpRequest();
        request1.setendpoint('https://api.box.com/2.0/folders'); 
        request1.setmethod('POST');
        request1.setHeader('Authorization','Bearer ' + accessToken);
        string bbody='{"name":"a.name", "parent": {"id": "0"}} ';
        
        request.setBody(bbody);
        Http p1=new Http();
        HttpResponse response1=p1.send(request1);
        jsonFolderResponse=response1.getBody();
        system.debug('jsonFolderResponse'+jsonFolderResponse1);  
            }
        catch (exception ex)
        {
            system.debug('ex '+ex.getMessage()+'  '+ex.getLineNumber());
        }
    }
    
    public class fromJSON
    {
        public string access_token;
        public integer expires_in;
        public cls_restricted_to[] restricted_to;
        public string refresh_token;
    }
    class cls_restricted_to
    {
    }
}
==================
class which calls authorize page

public class WebserviceBox 
{
    public string clientid;
    public string code;
    
    public string AutorizeBox()
    {
        clientid=BoxCCredentials__c.getValues('CredentialsBox').Client_Id__c;
        String endpointUrl1='https://app.box.com/api/oauth2/authorize?response_type=code&client_id='+clientid+'&state=symcsk02';
        pageReference pag=new pageReference(endpointUrl1);
        pag.setRedirect(true);
        return endpointUrl1;
    }  
    public void restCode(){
         code=ApexPages.currentpage().getparameters().get('code');
    }
}
===========================
trigger for which calls the class

trigger BoxInsert on Account (after insert) 
{   
    for(account a:trigger.new)
    {
        try
        {
            
        WebserviceBox wc=new WebserviceBox();
        string code=wc.AutorizeBox(); 
        system.debug('code ' + code);
        BoxController.boxAuthentication(a.id);
            
        }
        catch (exception ex)
        {
            system.debug('ex '+ex.getMessage()+'  '+ex.getLineNumber());
        }
    }
 
}
================================
errror: Attempt to dereference null object at  commented line in boxcontroller class

Pcon Can u help with this error i commented 
pconpcon
I'm assuming you're referring to the lines
 
clientid=BoxCCredentials__c.getValues('CredentialsBox').Client_Id__c; 
clientsecret=BoxCCredentials__c.getValues('CredentialsBox').Client_Secret__c;
ViewAPI_Key=BoxCCredentials__c.getValues('CredentialsBox').View_API_Key__c;
AccessToken=BoxCCredentials__c.getValues('CredentialsBox').Access_Token__c;
RefreshToken=BoxCCredentials__c.getValues('CredentialsBox').Refresh_Token__c;
system.debug('Client_Id__c'+clientid);
system.debug('clientsecret'+clientsecret);
system.debug('clientsecret'+ViewAPI_Key);

If you are referring to thses lines it's because you don't have an entry with the name CredentialsBox.  If you run the following in the Developer Console's anonymous Apex, you can see a list of all the possible values
 
System.debug(System.LoggingLevel.ERROR, BoxCCredentials__c.getAll().keySet());

These are case sensitive.  You can also run
 
System.debug(System.LoggingLevel.ERROR, BoxCCredentials__c.getValues('CredentialsBox'));

to see if the getValues call is returning null.

NOTE: Next time, please seperate these out into their own code samples (you can have multiple per post) and include the line number that you are seeing there error
Board salesforceBoard salesforce
Pcon ,
i think you didnt get it,
Call Visualforce page the redirects for oAuth login
Approve application
Return from oAuth flow to Visualforce page
Store access_token from payload into custom setting 
As you mentioned these are the steps to follow i agree
first we have to athuorise by entering box credentials(grantaccess) every time But here in trigger am unable to skip the grantaccess step
pconpcon
No, you don't get it.  You do NOT need to do the authorization step every time.  The authorization step only needs to occur once.
 
<apex:page controller="BoxController" action="{!redirectOnCallback}">
    <apex:outputPanel rendered="{!NOT(hasToken)}"><a href='{!authUrl}'>Login</a></apex:outputPanel>
    <apex:outputPanel rendered="{!hasToken}">Already has token</apex:outputPanel>
</apex:page>
BoxLogin.vfp
 
public class BoxController {
    @TestVisible private static String SETTING_NAME = 'CredentialsBox';
    @TestVisible private static String ACCESS_TOKEN_URL = 'https://api.box.com/oauth2/token';
    @TestVisible private static String AUTHORIZE_URL = 'https://api.box.com/oauth2/authorize';
    @TestVisible private static String FOLDER_URL = 'https://api.box.com/2.0/folders';

    @TestVisible private String access_token;
    @TestVisible private Boolean isCallback;
    
    /** The JSON result from a successful oauth call */
    public class OAuthResult {
        /** The access token */
        public String access_token {get; set;}
        
        /** The refresh token */
        public String refresh_token {get; set;}
    }
    
    /**
	* Validates the oauth code
	*
	* @param code The code to validate
	* @param redirect_uri The URL to redirect to after successful validation
	* @return The oauth result
	*/
	public static OAuthResult validateCode(String code, String redirect_uri) {
        String client_id = BoxCCredentials__c.getValues(SETTING_NAME).Client_Id__c;
        String client_secret = BoxCCredentials__c.getValues(SETTING_NAME).Client_Secret__c;

		List<String> urlParams = new List<String> {
			'grant_type=authorization_code',
			'code=' + EncodingUtil.urlEncode(code, 'UTF-8'),
			'client_id=' + EncodingUtil.urlEncode(client_id, 'UTF-8'),
			'client_secret=' + EncodingUtil.urlEncode(client_secret, 'UTF-8'),
			'redirect_uri=' + EncodingUtil.urlEncode(redirect_uri, 'UTF-8')
		};

		Http h = new Http();

		HttpRequest req = new HttpRequest();
		req.setEndpoint(ACCESS_TOKEN_URL);
		req.setMethod('POST');
		req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
		req.setHeader('Accept', 'application/json');
		String body = String.join(urlParams, '&');
		req.setBody(body);

		HttpResponse res = h.send(req);
		return (OAuthResult)(JSON.deserialize(res.getBody(), OAuthResult.class));
	}

    /**
    * Generic constructor
    */
    public BoxController() {
       this.isCallback = ApexPages.currentPage().getParameters().containsKey('code');

        if (BoxCCredentials__c.getValues(SETTING_NAME) != null) {
            this.access_token = BoxCCredentials__c.getValues(SETTING_NAME).Access_Token__c;
        }
    }

    /**
	* Gets the authroization URL
	*
	* @return The authorization url
	*/
    public String getAuthUrl() {
        Map<String, String> urlParams = new Map<String, String> {
			'client_id' => BoxCCredentials__c.getValues(SETTING_NAME).Client_Id__c,
			'redirect_uri' => getPageUrl(),
			'response_type' => 'code'
		};

		PageReference ref = new PageReference(AUTHORIZE_URL);
		ref.getParameters().putAll(urlParams);

		return ref.getUrl();
    }
    
    /**
    * Gets the page url
    * 
    * @return The page url
    */
    @testVisible
    private String getPageUrl() {
        String host = ApexPages.currentPage().getHeaders().get('Host');
        String path = ApexPages.currentPage().getUrl().split('\\?').get(0);
        
        return 'https://' + host + path;
    }
    
    /**
    * If the access token is set
    * 
    * @return If the access token is set
    */
    public Boolean getHasToken() {
        return (this.access_token != null);
    }
    
    /**
    * Validates the callback code and generates the access and refresh tokens
    * 
    * @return null to refresh the page
    */
    public PageReference redirectOnCallback() {
        if (this.isCallback) {
            String code = ApexPages.currentPage().getParameters().get('code');
            OAuthResult result = validateCode(code, this.getPageUrl());
            System.debug(result);
            
            BoxCCredentials__c creds = BoxCCredentials__c.getValues(SETTING_NAME);
            creds.Access_Token__c = result.access_token;
            creds.Refresh_Token__c = result.refresh_token;
            update creds;
        }
        
        return null;
    }
    
    private class ParentFolder {
        public String id;
        
        public ParentFolder(String id) {
            this.id = id;
        }
    }
    
    private class Folder {
        public String name;
        ParentFolder parent;
        
        public Folder(String name, String parentId) {
            this.name = name;
            this.parent = new ParentFolder(parentId);
        }
    }
    
    /**
    * Static method to create the folder inside of the box account
    * 
    * @param accountId The account id to create the folder for
    */
    @Future(callout = true)
    public static void createFolder(Id accountId) {
        if (BoxCCredentials__c.getValues(SETTING_NAME) == null) {
            return;
        }

        String access_token = BoxCCredentials__c.getValues(SETTING_NAME).Access_Token__c;
        Folder folder_info = new Folder(accountId, '0');
        
        HttpRequest request=new HttpRequest();
        request.setEndpoint(FOLDER_URL); 
        request.setMethod('POST');
        request.setHeader('Authorization', 'Bearer ' + access_token);
        String body = JSON.serialize(folder_info);
        System.debug(body);
        request.setBody(body);
        
        Http p = new Http();
        HttpResponse response = p.send(request);
    }
}
BoxController.cls
 
trigger BoxInsert on Account (after insert) {
    for (Account a : Trigger.new) {
        BoxController.createFolder(a.Id);
    }
}
BoxInsert.trigger
  1. Save these files
  2. Add api.box.com to your Remote Site Settings
  3. Goto /apex/BoxLogin
  4. Click Login
  5. You should see "Already has token" (It might refresh the page and Login still shows up.  If that happens just refresh the page)
  6. Insert an account
  7. View that folder has been created in your box.com account
After this, every time you insert an account, it will pull the access_token from the custom setting.  What this does not cover is how to regenerate the access_token with the refresh_token.  I'll leave that up to you.  Worst case, you delete the Access_Token__c from your credentials custom setting and then revisit the BoxLogin page to generate a new one.
Board salesforceBoard salesforce
Awesome
mismatch redirect_uri error ?vf page name will be the redirect_uri?
pconpcon
If you remove the redirect_uri from the box credentials (in the developer console) then it doesn't enforce that.  Otherwise it should be the name of the host you're on + visualforce page  ie  https://na30.salesforce.com/apex/BoxLogin
ShailendraTiwariShailendraTiwari
Hi  Board, 

HttpRequest req = new HttpRequest();
Http h=new Http();
String jsonData = '{"parents":[{"id":"root"}],"name":"DynamictTestWNF", "mimeType":"application/vnd.google-apps.folder"}';
req.setBody(jsonData);
req.setMethod('POST');
req.setEndpoint('https://www.googleapis.com/drive/v3/files');
req.setHeader('Content-length', String.valueOf(jsonData.length()));
req.setHeader('Content-type', 'application/json');
req.setHeader('Authorization', 'Bearer '+accessToken);
HttpResponse res = h.send(req);
System.debug('Response:- '+res.getBody());

We need to replace Id "0" to "root". So please put the "root" in JSON Body and check it.

Thanks,
Shailendra