Asynchronous Processing
If you call a DynamicPDF API endpoint multiple times, create large PDFs, or create PDFs require complex processing, consider using the endpoint's asynchronous process method.
Refer to each technology's documentation on asynchronous programming.
- C# (.NET)
- Java
- Node.js
- Go
- Python
C# uses the Task-based Asynchronous Pattern (TAP) for asynchronous programming and provides the Task
and Task<T>
objects for asynchronous operations.
These objects use the async
and await
keywords. Refer to Microsoft's Asynchronous Programming with async and await for more details.
Asynchronous methods are provided for the following endpoint classes.
DlexLayout
public Task<PdfResponse> ProcessAsync();
ImageInfo
public Task<ImageResponse> ProcessAsync();
Pdf
public Task<PdfResponse> ProcessAsync();
PdfInfo
public Task<PdfInfoResponse> ProcessAsync();
PdfText
public Task<PdfTextResponse> ProcessAsync();
PdfXmp
public Task<XmpResponse> ProcessAsync();
Refer to Asynchronous Processing documentation in Microsoft's C# Users Guide. Also refer to Asynchronous Request-Reply Pattern or Asynchronous Programming with async and await for more details.
Example
The following example illustrates using the ProcessAsync method with the dlex-layout endpoint (DlexLayout class). It is not production code, but illustrates the asynchronous nature when using the ProcessAsync method.
using DynamicPDF.Api;
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncExample
{
class Program
{
static void Main(string[] args)
{
Run("<api-key>", "c:/temp/");
}
static void Run(String apiKey, String basePath)
{
Task[] tasks = new Task[20];
for (int i = 0; i < 20; i++)
{
String user = "user" + i;
tasks[i] = RunAsync(apiKey, basePath, user).ContinueWith(x=>SaveFile(x.Result, basePath, user));
}
Task.WaitAll(tasks);
}
static Task<PdfResponse> RunAsync(String apiKey, String basePath, String userId)
{
LayoutDataResource layoutData = new LayoutDataResource(basePath + "report-with-cover-page.json");
DlexLayout dlexEndpoint = new DlexLayout("samples/report-with-cover-page/report-with-cover-page.dlex", layoutData);
dlexEndpoint.ApiKey = apiKey;
return dlexEndpoint.ProcessAsync();
}
static void SaveFile(PdfResponse response, string basePath, string userId)
{
if (response.IsSuccessful)
{
File.WriteAllBytes(basePath + userId + "-output.pdf", response.Content);
}
else
{
Console.WriteLine("ErrorId: " + response.ErrorId);
Console.WriteLine("ErrorMessage: " + response.ErrorMessage);
Console.WriteLine("ErrorJson: " + response.ErrorJson);
}
}
}
}
The important detail is the following code.
RunAsync(apiKey, basePath, user).ContinueWith(x=>SaveFile(x.Result, basePath, user));
The RunAsync
method calls the ProcessAsync
method and returns a Task<PdfResponse>
. This call ensures each call to the endpoint is asynchronous. When RunAsync
completes, it passes the PdfResponse
to the SaveFile
method to save the file to disk. The code Task.WaitAll(tasks);
is a convenience so that the main program awaits completion (it's not production code).
Java provides a CompletableFuture class for asynchronous operations. The method performs an action and returns a value when the completion stage completes.
DynamicPDF's API has asynchronous methods for the following endpoint classes.
DlexLayout
public CompletableFuture<PdfResponse> processAsync()
ImageInfo
public CompletableFuture<ImageResponse> processAsync()
Pdf
public CompletableFuture<PdfResponse> processAsync()
PdfInfo
public CompletableFuture<PdfInfoResponse> processAsync()
PdfText
public CompletableFuture<PdfTextResponse> processAsync()
PdfXmp
public CompletableFuture<XmlResponse> processAsync()
Example
The following example illustrates using the processAsync
method with the dlex-layout
endpoint (DlexLayout
class). It is not production code, but illustrates the asynchronous nature when using the processAsync
method.
package com.dynamicpdf.api.examples;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import org.apache.commons.io.FileUtils;
import com.dynamicpdf.api.DlexLayout;
import com.dynamicpdf.api.LayoutDataResource;
import com.dynamicpdf.api.PdfResponse;
public class AsyncExample {
public static void main(String[] args) {
Run("<apikey>", "c:/temp/dynamicpdf-api-samples/async-example/");
}
public static void Run(String apiKey, String basePath) {
LayoutDataResource layoutData = new LayoutDataResource(basePath + "report-with-cover-page.json");
DlexLayout dlexEndpoint = new DlexLayout("samples/report-with-cover-page/report-with-cover-page.dlex", layoutData);
dlexEndpoint.setApiKey(apiKey);
CompletableFuture<?>[] cf = new CompletableFuture[20];
for(int i = 0; i < 20; i++) {
String userId = "user" + i;
cf[i] = (dlexEndpoint.processAsync().thenAccept(
s->AsyncExample.SaveResult(s, basePath, userId)));
System.out.println("Processing: " + userId);
}
CompletableFuture.allOf(cf).join();
System.out.println("Finished");
}
public static void SaveResult(PdfResponse response, String basePath, String userId) {
System.out.println("Saving: " + userId);
if (response.getIsSuccessful()) {
try {
FileUtils.writeByteArrayToFile(new File(basePath + "/" + userId + "-output.pdf"), (byte[]) response.getContent());
} catch (IOException e) {
e.printStackTrace();
}
} else {
System.out.println(response.getErrorJson());
}
}
}
Node.js is asynchronous by default and uses the asynchronous processing model, also called the non-blocking I/O model. Use async
when you want to use the await
keyword inside that function. An async
function returns a promise. This promise allows you to await async
functions. Refer to the Node.js API documentation for more details.
The NodeJS endpoints are all asynchronous and use the await
keyword. For example, the following is the source for the pdf_text
endpoint (PdfText
).
/**Process the pdf resource to get pdf's text.
* @returns A Promise of PdfTextResponse callback.
*/
async process() {
let endpointUrl = this.baseUrl.endsWith("/") ? this.baseUrl + "v1.0/" + this.endPointName : this.baseUrl + "/v1.0/" + this.endPointName;
let url = new URL(endpointUrl + '/?StartPage=' + this.startPage + '&PageCount=' + this.pageCount);
return await this._postHttpRequest(url, this.#resource.data, 'application/pdf', PdfTextResponse);
}
The PdfText
class is a child of the EndPoint
class which contains the _postHttpRequest
method. The process
method waits for the _postHttpRequest
method to complete before returning the results. The async
keyword for the process
method identifies it as asynchronous.
Example
The following example, source code from the AddBookmarks
class in nodejs-client-examples
on github, illustrates. The await AddBookmarks.Run();
statement waits for the static async Run
method to complete, which in turn awaits the process
method to complete.
import fs from 'fs';
import {
Pdf,
PdfResource,
RgbColor,
UrlAction
} from "@dynamicpdf/api"
import { Console } from 'console';
// https://dpdf.io/docs/tutorials/cloud-api/pdf-tutorial-bookmarks
export class AddBookmarks {
static async Run() {
var pdf = new Pdf();
pdf.apiKey = "<api-key>";
var resourceA = new PdfResource("c:/temp/dynamicpdf-api-samples/add-bookmarks/DocumentA.pdf");
var resourceB = new PdfResource("c:/temp/dynamicpdf-api-samples/add-bookmarks/DocumentB.pdf");
var resourceC = new PdfResource("c:/temp/dynamicpdf-api-samples/add-bookmarks/DocumentC.pdf");
var inputA = pdf.addPdf(resourceA);
inputA.Id = "DocumentA";
var inputB = pdf.addPdf(resourceB);
inputB.Id = "DocumentB";
var inputC = pdf.addPdf(resourceC);
inputC.Id = "DocumentC";
var rootOutline = pdf.outlines.add("Three Bookmarks");
rootOutline.expanded = true;
var childOutlineA = rootOutline.children.add("DocumentA", inputA);
var childOutlineB = rootOutline.children.add("DocumentB", inputB, 2);
var childOutlineC = rootOutline.children.add("DocumentC", inputC);
childOutlineA.color = RgbColor.red;
childOutlineB.color = RgbColor.orange;
childOutlineC.color = RgbColor.green;
var outlineD = rootOutline.children.add("DynamicPDF API");
outlineD.color = RgbColor.blue;
outlineD.action = new UrlAction("https://dpdf.io/");
var res = await pdf.process();
if (res.isSuccessful) {
var outFile = "c:/temp/dynamicpdf-api-samples/add-bookmarks/add-bookmarks-javascript-output.pdf";
var outStream = fs.createWriteStream(outFile);
outStream.write(res.content);
outStream.close();
} else {
console.log(res.errorJson);
}
}
}
await AddBookmarks.Run();
The DynamicPDF API's Go client library relies upon the GO language's built-in asynchronous capabilities and there is no separate asynchronous process method.
DynamicPDF's API has asynchronous methods for the following endpoint classes.
DlexLayout
#Process the DLEX and layout data asynchronously to create PDF report.
async def ProcessAsync(self):
ImageInfo
#Process the pdf resource asynchronously to get image's information.
async def ProcessAsync(self):
Pdf
#Process data asynchronously to create pdf.
async def ProcessAsync(self):
PdfInfo
#Process the pdf resource asynchronously to get pdf's information.
async def ProcessAsync(self):
PdfText
#Process the pdf resource asynchronously to get pdf's text.
async def ProcessAsync(self):
PdfXmp
#Process the pdf resource asynchronously to get pdf's xmp data.
async def ProcessAsync(self):
Example
The following example illustrates using the ProcessAsync
method with the dlex-layout
endpoint (DlexLayout
class). It is not production code, but illustrates the asynchronous nature when using the ProcessAsync
method.
TBD