PDFPipe

Code-first automation / Pipedream

Generate a PDF from Pipedream

A workflow platform where the steps are real Node.js or Python, so anything the language can do the workflow can do.

Making the request

Whatever the language offers. A Node code step has fetch and can install any npm package; a Python step has the standard library and pip. There is no HTTP node with options to configure, which removes an entire category of question.

What it does with the response

The same as the language, which is to say it is not a platform question at all. What is a platform question is where the bytes live between steps. Step exports are serialised and stored, and they have a size limit, so a multi-megabyte PDF should not be returned from a step as a variable. Write it to the temporary directory and pass the path, or push it straight to its destination inside the step that created it.

Where the document can go afterwards

This is the part that differs most between platforms, and it is usually the reason one platform was chosen over another in the first place.

  • any destination with a client library, because the step is a real runtime with npm available
  • the temporary directory, which persists for the execution and can be read by later steps
  • an object store, an email provider or a CRM, using that service's own SDK rather than a connector
  • back to the caller, if the workflow is an HTTP-triggered endpoint returning the file

The limit that bites in production

Execution credits are consumed by runtime and by memory, so a workflow that renders a large document and holds it in memory costs more than one that streams it to storage. The temporary directory is not shared between concurrent executions and is not durable, so nothing may depend on a file surviving the run.

The shape that works

Render and dispatch in one step. The temptation is to render in step one, export the bytes, and consume them in step two, which pushes a large payload through the step export mechanism for no reason. Do the render and the upload in the same step and export only the resulting URL or id.

javascript
import fs from "fs";

export default defineComponent({
  props: {
    pdfpipe: { type: "app", app: "pdfpipe" },
  },
  async run({ steps, $ }) {
    const res = await fetch("https://api.pdfpipe.xyz/v1/pdf", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.PDFPIPE_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        html: steps.build_html.$return_value,
        options: { format: "A4", margin: "16mm" },
      }),
    });

    if (!res.ok) {
      throw new Error(`Render failed: ${res.status} ${await res.text()}`);
    }

    // Straight to /tmp rather than out through the step export, which
    // has a size limit and serialises whatever passes through it.
    const path = "/tmp/invoice.pdf";
    fs.writeFileSync(path, Buffer.from(await res.arrayBuffer()));

    // Export the path, never the bytes.
    return { path, bytes: fs.statSync(path).size };
  },
});

The mistake people make

Returning the PDF buffer from a step. It goes through the export mechanism, gets serialised, counts against the export size limit and shows up in the execution log viewer as an enormous unreadable blob. Return a path or a URL and keep the bytes on disk or at their destination.

Frequently asked

Can Pipedream handle the PDF bytes directly?

The same as the language, which is to say it is not a platform question at all. What is a platform question is where the bytes live between steps. Step exports are serialised and stored, and they have a size limit, so a multi-megabyte PDF should not be returned from a step as a variable. Write it to the temporary directory and pass the path, or push it straight to its destination inside the step that created it.

Should I store the document or pass the bytes through?

It depends on what the platform does with a large value. On a platform that serialises everything passing between steps, pushing several megabytes through the workflow is slow and sometimes capped, so storing the document and passing a URL is better. On a platform that hands you a file object natively, passing it straight to its destination is simpler and avoids a second fetch. The page above says which of those this platform is.

Where does the API key live?

In the platform's own secret or environment storage, never in a step body where it is visible in an execution log. Every platform on this list has somewhere to put it, and the execution logs of an automation platform are seen by more people than a codebase is.

Other platforms

Platforms of the same kind, and one from each of the other kinds.

100 free documents a month, and a playground that runs a real render without a key, which is the fastest way to get an HTML sample worth wiring up.