4

Having successfully logged in, and have got the list of documents from an envelope, I am trying to retrieve a signed document from DocuSign, using the DocuSign Node SDK, using this code:

envelopesApi.getDocument(accountId, envelopeId, documents[0].documentId, function(err, data, response) {
  log.info({data: data.substring(0, 100)}, 'getDocument data');
  log.info({response}, 'getDocument response');
  fs.writeFile('/home/martin/downloaded.pdf', data, (err) => {
    next(err);
  });
});

The data variable is a string. It is not base64 encoded. The first logging statement (using the Bunyan logging module) shows that the string starts with these characters:

%PDF-1.4
%ûüýþ
4 0 obj
<<
/Parent 3 0 R
/Resources 5 0 R
/MediaBox [0.00000 0.00000 595.00000 842.00

therefore I can see that it's not base64 encoded. It seems strange to me to be holding the contents of a pdf file in a string. I was expecting a Buffer object.

When I open (in Chrome) the file that this code saved, it appears to be a valid pdf file (i.e. Chrome doesn't error saying the file is corrupt), and it has the right number of pages, but it is completely unreadable. There is no legible text at all on the page, indicating that something has got corrupted.

Looking at the EnvelopesApi.js and ApiClient.js files from the SDK I can see that it's requesting a PDF, and that there is code in the ApiClient specifically for handling PDFs - which appears to be reading from a readable stream & appending to a string.

I'm aware that there's an alternative to not use the NOde SDK, and just use the REST API directly (as per the examples in the official REST API Recipe: Getting an Envelope's Document List), but I'd like to use the SDK if possible.

Am I missing something that I should be doing with this data parameter?

Martin Pain
  • 713
  • 4
  • 18

4 Answers4

2

See the api recipe to download a document here

Here is the sample code to download a document.

  envelopesApi.getDocument(accountId, envelopeId, documentId, function (error, document, response) {
    if (error) {
      console.log('Error: ' + error);
      return;
    }

    if (document) {
      try {
        var fs = require('fs');
        var path = require('path');
        // download the document pdf
        var filename = accountId + '_' + envelopeId + '_' + documentId + '.pdf';
        var tempFile = path.resolve(__dirname, filename);
        fs.writeFile(tempFile, new Buffer(document, 'binary'), function (err) {
          if (err) console.log('Error: ' + err);
        });
        console.log('Document ' + documentId + ' from envelope ' + envelopeId + ' has been downloaded to ' + tempFile);
      } catch (ex) {
        console.log('Exception: ' + ex);
      }
    }
  });
Praveen Reddy
  • 7,295
  • 2
  • 21
  • 43
0

We faced the same issue today and it was not because of the Docusign API but because we used Amazon Lambda functions; to make it work, we had to change a bit our serverless.yml file and add a binaryMediaTypes section like this:

provider:
  name: aws
  runtime: nodejs12.x
  region: eu-west-3
  profile:xxxxx
  versionFunctions: false
  apiGateway:
    binaryMediaTypes:
      - 'text/html'

Hope it will help

Bastien L.
  • 119
  • 1
  • 2
  • 9
0

var https = require('follow-redirects').https; var fs = require('fs');

      var options = {
        'method': 'GET',
        'hostname': 'demo.docusign.net',
        'path': '/restapi/v2/accounts/{account_id}/envelopes/{envelope_id}/documents/combined',
        'headers': {
          'X-DocuSign-Authentication': ' {"Username": "*******","Password": "******","IntegratorKey": "*******"}'
        },
        'maxRedirects': 20
      };

      var req = https.request(options, function (res) {
        var chunks = [];

        res.on("data", function (chunk) {
          chunks.push(chunk);
        });

        res.on("end", function (chunk) {
          var body = Buffer.concat(chunks);

          var filename = '_combined.pdf';
        var tempFile = filename;
        fs.writeFile(tempFile, Buffer.from(body,"binary"), function (err) {
          if (err) console.log('Error: ' + err);
        });
        console.log('Document from envelope has been downloaded');

        });

        res.on("error", function (error) {
          console.error(error);
        });
      });

      req.end();
Shraddha Bandekar
  • 396
  • 2
  • 6
  • 17
0

When calling envelopesApi.getDocument in Docusign Node SDK, in what format is the data returned?

The eSignature NodeJS SDK's getDocument method returns a binary-encoded string by default. Alternatively you can request that it returns a base64-encoded string.

How do I write it to a file?

If it's a binary-encoded string, you will need to decode it as a raw binary buffer using Buffer.from(STRING, 'binary') and then write the result to memory. If it's a base64-encoded string, it's the same but you use 'base64' instead.

Promise-based version:

const fs = require('fs/promises');
const path = require('path');
const { Buffer } = require('buffer');
const docusign = require('docusign-esign');

async function writeDocument(dsApiClient, { accountId, envelopeId, documentId }) {
  try {
    const envelopesApi = new docusign.EnvelopesApi(dsApiClient);
    const binString = await envelopesApi.getDocument(accountId, envelopeId, documentId);
    const filepath = path.resolve(__dirname, `document_${documentId}`);
    await fs.writeFile(filepath, Buffer.from(binString, 'binary'));
  } catch (error) {
    throw new Error('Unable to write document to disk', { cause: error });
  });
}

Which you'd call as follows:

// Initialize DocuSign Api Client
const dsApiClient = new docusign.ApiClient();
dsApiClient.setBasePath(BASE_PATH);
dsApiClient.addDefaultHeader('Authorization', `Bearer ${ACCESS_TOKEN}`);

(async () => {
  try {
    await writeDocument(dsApiClient, { accountId, envelopeId, documentId });
  } catch(error) {
    console.log('Could not save DocuSign document', error);
  }
});
uzluisf
  • 2,586
  • 1
  • 9
  • 27