+ Start a Discussion
Manohar kumarManohar kumar 

onedrive rest api call to upload a file...

hi i am having trouble with calling onedrive api.here is my code,i dont understand how to use boundary in this.i am a newbie with api and going with the onedrive documentation.Any help would be appreciated.thanks

public void uploadFile(string accessToken){
set<id> allids = new set<id>();
allids.add('00Q2800000Fwl1b');
List<Attachment> content = [Select Id, Name, ContentType, BodyLength, Body, CreatedById, Description From Attachment Where ParentId IN :allids limit 1];
system.debug('@@content'+content);
httpRequest req = new httpRequest();
req.setEndPoint('https://apis.live.net/v5.0/me/skydrive/files?access_token='+accessToken);
req.setHeader('Content-Disposition', 'form-data; name="file"; filename="content[0].Name"');
req.setHeader('Content-Type', 'multipart/form-data; boundary=A300x');
//req.setLength('Content-Length',string.valueOf(content[0].BodyLength));
string Body = string.valueOf(content[0].Body); req.setBody(Body);
req.setHeader('Content-Length',string.valueOf(content[0].BodyLength));
req.setCompressed(true); req.setMethod('POST');
HttpResponse res = null;
http h= new Http();
res= h.send(req); system.debug('@@@@'+res);
System.debug('---------------------'+res.getbody());
}

error in the debug:

"error": { "code": "request_body_invalid", "message": "The request entity body for multipart form-data POST isn't valid. The expected format is:\u000d\u000a--[boundary]\u000d\u000aContent-Disposition: form-data; name=\"file\"; filename=\"[FileName]\"\u000d\u000aContent-Type: application/octet-stream\u000d\u000a[CR][LF]\u000d\u000a[file contents]\u000d\u000a--[boundary]--[CR][LF]" }

 

Best Answer chosen by Manohar kumar
Daniel BallingerDaniel Ballinger
There is a good article on how to send a multipart POST in POST Mutipart/form-data with HttpRequest (http://blog.enree.co/2013/01/salesforce-apex-post-mutipartform-data.html#update20141017) by Enrico Murru.

The relavant method is:
 
public static void uploadFile(Blob file_body, String file_name, String reqEndPoint){
      // Repost of code  with fix for file corruption issue
      // Orignal code postings and explanations
      // http://enreeco.blogspot.in/2013/01/salesforce-apex-post-mutipartform-data.html
      // http://salesforce.stackexchange.com/questions/24108/post-multipart-without-base64-encoding-the-body
      // Additional changes commented GW: that fix issue with occasional corruption of files
      String boundary = '----------------------------741e90d31eff';
      String header = '--'+boundary+'\nContent-Disposition: form-data; name="file"; filename="'+file_name+'";\nContent-Type: application/octet-stream';
      // GW: Do not prepend footer with \r\n, you'll see why in a moment
      // String footer = '\r\n--'+boundary+'--'; 
      String footer = '--'+boundary+'--';             
      String headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
      while(headerEncoded.endsWith('='))
      {
       header+=' ';
       headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
      }
      String bodyEncoded = EncodingUtil.base64Encode(file_body);
      // GW: Do not encode footer yet
      // String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
 
      Blob bodyBlob = null;
      String last4Bytes = bodyEncoded.substring(bodyEncoded.length()-4,bodyEncoded.length());
 
      // GW: Replacing this entire section
      /*
      if(last4Bytes.endsWith('='))
      {
           Blob decoded4Bytes = EncodingUtil.base64Decode(last4Bytes);
           HttpRequest tmp = new HttpRequest();
           tmp.setBodyAsBlob(decoded4Bytes);
           String last4BytesFooter = tmp.getBody()+footer;   
           bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded.substring(0,bodyEncoded.length()-4)+EncodingUtil.base64Encode(Blob.valueOf(last4BytesFooter)));
      }
      else
      {
            bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);
      }
      */
     // GW: replacement section to get rid of padding without corrupting data
     if(last4Bytes.endsWith('==')) {
        // The '==' sequence indicates that the last group contained only one 8 bit byte
        // 8 digit binary representation of CR is 00001101
        // 8 digit binary representation of LF is 00001010
        // Stitch them together and then from the right split them into 6 bit chunks
        // 0000110100001010 becomes 0000 110100 001010
        // Note the first 4 bits 0000 are identical to the padding used to encode the
        // second original 6 bit chunk, this is handy it means we can hard code the response in
        // The decimal values of 110100 001010 are 52 10
        // The base64 mapping values of 52 10 are 0 K
        // See http://en.wikipedia.org/wiki/Base64 for base64 mapping table
        // Therefore, we replace == with 0K
        // Note: if using \n\n instead of \r\n replace == with 'oK'
        last4Bytes = last4Bytes.substring(0,2) + '0K';
        bodyEncoded = bodyEncoded.substring(0,bodyEncoded.length()-4) + last4Bytes;
        // We have appended the \r\n to the Blob, so leave footer as it is.
        String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
        bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);
      } else if(last4Bytes.endsWith('=')) {
        // '=' indicates that encoded data already contained two out of 3x 8 bit bytes
        // We replace final 8 bit byte with a CR e.g. \r
        // 8 digit binary representation of CR is 00001101
        // Ignore the first 2 bits of 00 001101 they have already been used up as padding
        // for the existing data.
        // The Decimal value of 001101 is 13
        // The base64 value of 13 is N
        // Therefore, we replace = with N
        // Note: if using \n instead of \r replace = with 'K'
        last4Bytes = last4Bytes.substring(0,3) + 'N';
        bodyEncoded = bodyEncoded.substring(0,bodyEncoded.length()-4) + last4Bytes;
        // We have appended the CR e.g. \r, still need to prepend the line feed to the footer
        footer = '\n' + footer;
        String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
        bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);              
      } else {
        // Prepend the CR LF to the footer
        footer = '\r\n' + footer;
        String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
        bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);  
      }
 
      HttpRequest req = new HttpRequest();
      req.setHeader('Content-Type','multipart/form-data; boundary='+boundary);
      req.setMethod('POST');
      req.setEndpoint(reqEndPoint);
      req.setBodyAsBlob(bodyBlob);
      req.setTimeout(120000);
 
      Http http = new Http();
      HTTPResponse res = http.send(req);
}

So to modify your existing method:
 
public void uploadFile(string accessToken){
	set<id> allids = new set<id>();
	allids.add('00Q2800000Fwl1b');
	List<Attachment> content = [Select Id, Name, ContentType, BodyLength, Body, CreatedById, Description From Attachment Where ParentId IN :allids limit 1];
	
	system.debug('@@content'+content);

	String reqEndPoint = 'https://apis.live.net/v5.0/me/skydrive/files?access_token='+accessToken;
    uploadFile(content[0].Body, content[0].Name, reqEndPoint);	
}

 

All Answers

Daniel BallingerDaniel Ballinger
There is a good article on how to send a multipart POST in POST Mutipart/form-data with HttpRequest (http://blog.enree.co/2013/01/salesforce-apex-post-mutipartform-data.html#update20141017) by Enrico Murru.

The relavant method is:
 
public static void uploadFile(Blob file_body, String file_name, String reqEndPoint){
      // Repost of code  with fix for file corruption issue
      // Orignal code postings and explanations
      // http://enreeco.blogspot.in/2013/01/salesforce-apex-post-mutipartform-data.html
      // http://salesforce.stackexchange.com/questions/24108/post-multipart-without-base64-encoding-the-body
      // Additional changes commented GW: that fix issue with occasional corruption of files
      String boundary = '----------------------------741e90d31eff';
      String header = '--'+boundary+'\nContent-Disposition: form-data; name="file"; filename="'+file_name+'";\nContent-Type: application/octet-stream';
      // GW: Do not prepend footer with \r\n, you'll see why in a moment
      // String footer = '\r\n--'+boundary+'--'; 
      String footer = '--'+boundary+'--';             
      String headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
      while(headerEncoded.endsWith('='))
      {
       header+=' ';
       headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
      }
      String bodyEncoded = EncodingUtil.base64Encode(file_body);
      // GW: Do not encode footer yet
      // String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
 
      Blob bodyBlob = null;
      String last4Bytes = bodyEncoded.substring(bodyEncoded.length()-4,bodyEncoded.length());
 
      // GW: Replacing this entire section
      /*
      if(last4Bytes.endsWith('='))
      {
           Blob decoded4Bytes = EncodingUtil.base64Decode(last4Bytes);
           HttpRequest tmp = new HttpRequest();
           tmp.setBodyAsBlob(decoded4Bytes);
           String last4BytesFooter = tmp.getBody()+footer;   
           bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded.substring(0,bodyEncoded.length()-4)+EncodingUtil.base64Encode(Blob.valueOf(last4BytesFooter)));
      }
      else
      {
            bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);
      }
      */
     // GW: replacement section to get rid of padding without corrupting data
     if(last4Bytes.endsWith('==')) {
        // The '==' sequence indicates that the last group contained only one 8 bit byte
        // 8 digit binary representation of CR is 00001101
        // 8 digit binary representation of LF is 00001010
        // Stitch them together and then from the right split them into 6 bit chunks
        // 0000110100001010 becomes 0000 110100 001010
        // Note the first 4 bits 0000 are identical to the padding used to encode the
        // second original 6 bit chunk, this is handy it means we can hard code the response in
        // The decimal values of 110100 001010 are 52 10
        // The base64 mapping values of 52 10 are 0 K
        // See http://en.wikipedia.org/wiki/Base64 for base64 mapping table
        // Therefore, we replace == with 0K
        // Note: if using \n\n instead of \r\n replace == with 'oK'
        last4Bytes = last4Bytes.substring(0,2) + '0K';
        bodyEncoded = bodyEncoded.substring(0,bodyEncoded.length()-4) + last4Bytes;
        // We have appended the \r\n to the Blob, so leave footer as it is.
        String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
        bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);
      } else if(last4Bytes.endsWith('=')) {
        // '=' indicates that encoded data already contained two out of 3x 8 bit bytes
        // We replace final 8 bit byte with a CR e.g. \r
        // 8 digit binary representation of CR is 00001101
        // Ignore the first 2 bits of 00 001101 they have already been used up as padding
        // for the existing data.
        // The Decimal value of 001101 is 13
        // The base64 value of 13 is N
        // Therefore, we replace = with N
        // Note: if using \n instead of \r replace = with 'K'
        last4Bytes = last4Bytes.substring(0,3) + 'N';
        bodyEncoded = bodyEncoded.substring(0,bodyEncoded.length()-4) + last4Bytes;
        // We have appended the CR e.g. \r, still need to prepend the line feed to the footer
        footer = '\n' + footer;
        String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
        bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);              
      } else {
        // Prepend the CR LF to the footer
        footer = '\r\n' + footer;
        String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
        bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);  
      }
 
      HttpRequest req = new HttpRequest();
      req.setHeader('Content-Type','multipart/form-data; boundary='+boundary);
      req.setMethod('POST');
      req.setEndpoint(reqEndPoint);
      req.setBodyAsBlob(bodyBlob);
      req.setTimeout(120000);
 
      Http http = new Http();
      HTTPResponse res = http.send(req);
}

So to modify your existing method:
 
public void uploadFile(string accessToken){
	set<id> allids = new set<id>();
	allids.add('00Q2800000Fwl1b');
	List<Attachment> content = [Select Id, Name, ContentType, BodyLength, Body, CreatedById, Description From Attachment Where ParentId IN :allids limit 1];
	
	system.debug('@@content'+content);

	String reqEndPoint = 'https://apis.live.net/v5.0/me/skydrive/files?access_token='+accessToken;
    uploadFile(content[0].Body, content[0].Name, reqEndPoint);	
}

 
This was selected as the best answer
Manohar kumarManohar kumar

thanks for the reply Daniel.. it worked.
here is my code..

 public void uploadFile(string accessToken){
       set<id>  allids = new set<id>();
       allids.add('00Q2803450Fwl1b');
       List<Attachment> content = [Select Id, Name, ContentType, BodyLength, Body, CreatedById, Description From Attachment Where ParentId  IN :allids limit 1];
    system.debug('@@content'+content);        
    Blob file_body = content[0].Body;
    String file_name = content[0].Name;
    String reqEndPoint = 'https://apis.live.net/v5.0/me/skydrive/files?access_token='+accessToken;
      String boundary = '----------------------------741e90d31eff';
      String header = '--'+boundary+'\r\nContent-Disposition: form-data; name="file"; filename="'+content[0].Name+'"\r\nContent-Type: application/octet-stream'; // added '\r's removed ';' see Tim Smith's comment
      String footer = '\r\n--'+boundary+'--';              
      String headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
      while(headerEncoded.endsWith('='))
      {
       header+=' ';
       headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
      }
      String bodyEncoded = EncodingUtil.base64Encode(file_body);
      String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));

      Blob bodyBlob = null;
      String last4Bytes = bodyEncoded.substring(bodyEncoded.length()-4,bodyEncoded.length());
      if(last4Bytes.endsWith('='))
      {
           Blob decoded4Bytes = EncodingUtil.base64Decode(last4Bytes);
           HttpRequest tmp = new HttpRequest();
           tmp.setBodyAsBlob(decoded4Bytes);
           String last4BytesFooter = tmp.getBody()+footer;   
           bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded.substring(0,bodyEncoded.length()-4)+EncodingUtil.base64Encode(Blob.valueOf(last4BytesFooter)));
      }
      else
      {
            bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);
      }

      HttpRequest req = new HttpRequest();
      req.setHeader('Content-Type','multipart/form-data; boundary='+boundary);
      req.setMethod('POST');
      req.setEndpoint(reqEndPoint);
      req.setBodyAsBlob(bodyBlob);
      //req.setTimeout(120000);

      Http http = new Http();
      HTTPResponse res = http.send(req);
       system.debug('@@@@'+res);
        System.debug('---------------------'+res.getbody());

            
   }   

Manohar kumarManohar kumar

hi Daniel,

i am having one more problem.i am getting HTTP Error 400. The request is badly formed when try to get the  authentication code .

its working perfectly when i call from my browser.

public void GetCode(){
	      http h = new http();
	      httpRequest req = new httpRequest();
	    String Clientkey = EncodingUtil.urlEncode(key,'UTF-8');  
        String uri = EncodingUtil.urlEncode(redirect_uri,'UTF-8');  
        //req.setHeader('Content-type', 'text/xml');
        //req.setHeader('Accept-Charset', 'UTF-8');
	      req.setMethod('GET');
	      string str ='https://login.live.com/oauth20_authorize.srf?client_id='+Clientkey+'&scope=wl.signin wl.offline_access onedrive.readwrite&response_type=token&redirect_uri='+redirect_uri;
	      system.debug('@@str'+str);
	      req.setEndPoint(str);
	      httpResponse res = h.send(req);
	      system.debug('##res'+res);  
	      system.debug('######'+res.getBody());
      }