Mail Merge Word Document and Convert output to PDF in Node

I am trying to do a mail merge, but I need the resulting output to be a PDF. So I am trying to take the result of the merge, and pass it to the convert function, but I am running into the following error:

body: WordsApiErrorResponse {
    error: ApiError {
      message: 'Unexpected end of Stream, the content may have already been read by another component. '
    }
}

Here is the code:

const wordsApi = new WordsApi(clientId, secret);

let requestTemplate = fs.createReadStream("TestExecuteTemplate.docx");
let requestData = fs.createReadStream("TestExecuteTemplateData.json");

const mailMergeRequest = new ExecuteMailMergeOnlineRequest({
    template: requestTemplate,
    data: requestData,
    withRegions: true
});

wordsApi.executeMailMergeOnline(mailMergeRequest)
.then((mailMergeRequestResult) => {
    console.log("merge complete");
    const convertRequest = new ConvertDocumentRequest({
        document: Readable.from(mailMergeRequestResult.body),
        format: "pdf"
    });
    wordsApi.convertDocument(convertRequest)
    .then((convertRequestResult) => {
        console.log("convert complete");
        fs.writeFile('output.pdf', convertRequestResult.body, function (err) {
            if (err) return console.log(err);
            console.log('file saved');
        });
    })
    .catch((err) => {
        console.log(err);
    });

})
.catch((err) => {
    console.log(err);
});

What should I be doing differently?

@danobri

Please amend the convertRequest code as following, it will fix the issue.

 const convertRequest = new ConvertDocumentRequest({
        //document: Readable.from(mailMergeRequestResult.body),
	document: mailMergeRequestResult.body,
	format: "pdf"
    });

That doesn’t work, as it’s a type mismatch - body is a Buffer, and document is a Readable.

image.png (67.7 KB)

The file conversion does complete successfully without Readable.from(), but it causes the type mismatch shown in the screenshot. So maybe there is something not quite right about the typings file?

@danobri

Thanks for your feedback. We have logged an internal ticket WORDSCLOUD-1747 for more investigation. We will share the results with you asap.

The issues you have found earlier (filed as WORDSCLOUD-1747) have been fixed in this update. This message was posted using Bugs notification tool by Ivanov_John

@danobri

About the above issue, it is the expected behavior of Node SDK. The return type of executeMailMergeOnline method is Promise< model.WordsIncomingMessage< Buffer > >. And the parameter type for ConvertDocumentRequest.document is Readable. So Node.js can’t convert Buffer to Readable and displays the error.

Recently we have added a new feature, a batch of requests, and changed the result type for most of the methods. You can use this feature for the scenario.

The best idea is to use a batch request for two requests: ExecuteMailMergeOnlineRequest and ConvertDocumentRequest. Use request1.useAsSource() to redirect the result of the first request to the second request. Both requests are executed on the API side. It is a simple, fast, and convenient way to do it. Look at batch tests for examples.

If you would like to follow an old-fashioned way with consecutive requests, you need to convert Buffer to stream type. There are many ways. For instance, buffer-to-stream package ( buffer-to-stream - npm )

You don’t need an external package to convert a Buffer to a Readable stream. The native Readable.from method works fine for this purpose. I have confirmed this is working in the latest version.

That said - using the batch function does seem like a better way to handle multiple requests. Thanks for providing the additional information.

@danobri

Thanks for your feedback. It is good to know that your requirement is fulfilled.

One follow up question - is a batch request treated as one API request from a pricing standpoint, or is each step of the batch treated as API request from a billing standpoint?

@danobri

Please note, in the batch request each API call is charged as a separate credit not all APIs as a whole.