4

I could really use some help here.

What is the difference between cURL and using the javascript Request module that would make the attachments coming out of one perfect and the other garbled? Here's what I'm facing:

When I use cURL at the command line, my file comes perfectly:

curl https:///services/data/v37.0/sobjects/Attachment/00Pm0000009RZFz/Body -H 'Authorization: Bearer '

This is beautiful (mainly because the attachment I've stored at that record is my picture)!

However, when I issue the following code I get garbage:

  var options = { method: 'GET',
                  url: resourceURL,
                  headers:
                  {
                    'Authorization': 'Bearer ' + conn.accessToken,
                  }
                };
  curl.request(options, function(err, data) {
    if (err) throw err;
    res.send(data);
  });

I get the following to the browser:

����JFIF��C  !"$"$��C����"�� ���}!1AQa"q2���#B��R��$3br� %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz��������������������������������������������������������������������������� ���w!1AQaq"2�B���� #3R�br� $4�%�&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz�� (I'll spare you the rest of the binary)

It has JFIF so I believe it's the correct data, just in the wrong encoding. According to SFDC they send just the raw data, and I assume that is why it's getting written out to a file fine through cURL. But something is screwy when trying to send this thing out to the client.

Here are some additional facts:

1) I am writing this as part of a node server. I can't use local storage on the server, as it's going to be hosted on Heroku. 2) I am fine returning a data URI (i.e. ) and in fact that would be preferable because they are looking for permalinks here and you can't get at these attachments without a token otherwise. 3) I KNOW that I am getting binary data from Salesforce, I just don't know how to successfully transfer it within the context of the node app.

Can anyone offer any advice? Thank you very much in advance!

Scott

3

You can convert the binary data to base64 and send that as part of the response. You can use the base4 string to render the image on the browser. Change the code in node app to :

res.send(new Buffer(data, 'binary').toString('base64'));

And in the page you can display the image using the dataURIs

<img width="50" height="50" alt="star" src="data:image/jpg;base64,base64StringReturnedFromYourNodeAPP" />

Hope it helps!

  • Thank you so much for responding Anamadeya! I gave this a try, and while I thought it looked promising, it's garbling the data. Here's what I'm getting: – Scott Cromie Sep 3 '16 at 18:41
  • /f39/QAQSkZJRgABAgAAAQABAAD9/QBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8KCwkMEQ8SEhEPERATFhwXExQaFRARGCEYGhwdHx8fExciJCIeJBweHx79/QBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh79/QARCAD9AP0DASIAAhEBAxEB/f0AHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/f0A/RAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDL9/f0II0L9/RVS/f0kM2Jy/... – Scott Cromie Sep 3 '16 at 19:04
  • This is the garbled data encoded in base64 - so it's much like the module I'm using - curlrequest - is doing some conversion before I get access to the data. – Scott Cromie Sep 3 '16 at 19:06
  • This is the curl command that the library produces: `curl --silent --show-error --no-buffer --url sfdcmyurl.my.salesforce.com/services/data/v37.0/sobjects/… --request GET --location --max-redirs 3 --header Accept: image/jpeg --header Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 --header Accept-Language: en-US,en;q=0.8 --header Authorization: Bearer <access token> --user-agent Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.809.0 Safari/535 – Scott Cromie Sep 3 '16 at 19:08
  • also, for reference, the cURL command that works perfectly and downloads the document is this: curl https://myUrl.my.salesforce.com/services/data/v37.0/sobjects/Attachment/00Pm0000009RZFz/Body -H 'Authorization: Bearer AuthToken' – Scott Cromie Sep 3 '16 at 19:25
1

I found the answer to my question, and it comes down to an understanding of what I'm trying to do. stomita posted in the jsForce issues on github the following:

(see the context here: https://github.com/jsforce/jsforce/issues/223)

stomita commented on Sep 8, 2015

You can convert the stream to string.

var contentStream = conn.sobject('ContentNote').record(id).blob('Content');
var buf = [];
contentStream.on('data', function(data, enc) {
  buf.push(data.toString(enc));
});
contentStream.on('end', function() {
  var contentStr = buf.join('');
  // handle contentStr
});

You see, what was happening for me is the binary was coming through and being converted under the covers, so when the byte came over the pipe it was recognized as a string value (which then mapped to the wrong binary value), instead of the string value representation of the binary character. Or, in other words, the binary value of FF (the correct value) was brought down as the UTF-8 value of EF (the wrong value) and interpreted as binary EF on the client browser.

No bueno.

So, apparently I needed to spend 2 days of pain to figure out exactly how to do this, but then I saw stomita's post again and it all clicked for me. I made the modification and incorporated one of the posted comments into my code for attachments:

If you want to get data from the Attachment-object, you could do this almost the same way, but you should use Buffer.concat(buf), instead of buf.join('') and skip the toString-decoding. --kennethdammyr

So the final code is this:

//Assume sfdcConn is a valid connection to Salesforce using the jsForce library.

    try {
    return sfdcConn(app, req, res).then(function(result) {
    // In order to return a clickable link we need to issue a GET from our server
      var conn = result;
      var theAtt = conn.sobject('Attachment').record(req.query.attachId);
      var attBlob = theAtt.blob('Body');
      var buf = [];
      attBlob.on('data', function(data) {
        buf.push(data);
      });
      attBlob.on('end', function() {
        var contentStr = Buffer.concat(buf);
        res.send(contentStr);
      });
    }, function(err) {
      throw (err);
    });
  } catch (err) {
    console.error(err);
    return {'isSuccess': false,
            'errorMessage': 'No connection could be made to Salesforce.com: ' + err};
  }

I hope this helps someone else to avoid the pain of knowing you're doing it the way they say to but not having it work the way you intend it to.

Scott

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.