惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Blog — PlanetScale
Blog — PlanetScale
B
Blog
A
About on SuperTechFans
大猫的无限游戏
大猫的无限游戏
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Help Net Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园 - 三生石上(FineUI控件)
有赞技术团队
有赞技术团队
酷 壳 – CoolShell
酷 壳 – CoolShell
WordPress大学
WordPress大学
IT之家
IT之家
D
Docker
Google DeepMind News
Google DeepMind News
罗磊的独立博客
T
The Blog of Author Tim Ferriss
aimingoo的专栏
aimingoo的专栏
博客园 - 叶小钗
Recent Announcements
Recent Announcements
阮一峰的网络日志
阮一峰的网络日志
D
DataBreaches.Net
博客园 - 司徒正美
Engineering at Meta
Engineering at Meta

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Generate PDFs from JSON in Any Language — One REST API (P...
Gerardo Barrera · 2026-06-24 · via DEV Community
Cover image for Generate PDFs from JSON in Any Language — One REST API (Python, Node, PHP, Go)

Gerardo Barrera

Every backend eventually has to spit out a PDF — an invoice, a receipt, a report, a certificate. And in every language, the options are bad:

  • Headless Chrome / Puppeteer — you render HTML to PDF. Works until your data gets long: tables split across pages, fonts go missing, and you're babysitting a browser farm in production.
  • Native libraries (ReportLab in Python, PDFKit in Node, FPDF in PHP, gofpdf in Go) — you position everything by hand in code. Generic fonts, fragile layouts, and the design lives in your codebase forever.

There's a cleaner separation: design the document once, then feed it data over HTTP. Because it's just a REST call, the exact same approach works in any language.

The idea: template + data → PDF

  1. Design a reusable template once — visually, or by describing it to an AI — with placeholders like {{customer}} and {{total}}.
  2. POST your JSON to one endpoint with the template ID.
  3. Get back a finished, editable PDF.

No HTML/CSS, no headless browser, no fonts to ship. Here's the same request in five languages.

curl

curl https://api.pdfmakerapi.com/v1/render \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "template_id": "invoice_default",
        "data": { "number": "INV-1042", "customer": "Acme Inc.", "total": 49.00 } }' \
  --output invoice.pdf

Node.js

const res = await fetch("https://api.pdfmakerapi.com/v1/render", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PDF_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    template_id: "invoice_default",
    data: { number: "INV-1042", customer: "Acme Inc.", total: 49.0 },
  }),
});
require("fs").writeFileSync("invoice.pdf", Buffer.from(await res.arrayBuffer()));

Python

import os, requests

res = requests.post(
    "https://api.pdfmakerapi.com/v1/render",
    headers={"Authorization": f"Bearer {os.environ['PDF_API_KEY']}"},
    json={
        "template_id": "invoice_default",
        "data": {"number": "INV-1042", "customer": "Acme Inc.", "total": 49.00},
    },
)
open("invoice.pdf", "wb").write(res.content)

PHP

<?php
$res = file_get_contents("https://api.pdfmakerapi.com/v1/render", false, stream_context_create([
  "http" => [
    "method"  => "POST",
    "header"  => "Authorization: Bearer {$_ENV['PDF_API_KEY']}\r\nContent-Type: application/json",
    "content" => json_encode([
      "template_id" => "invoice_default",
      "data" => ["number" => "INV-1042", "customer" => "Acme Inc.", "total" => 49.00],
    ]),
  ],
]));
file_put_contents("invoice.pdf", $res);

Go

body, _ := json.Marshal(map[string]any{
    "template_id": "invoice_default",
    "data":        map[string]any{"number": "INV-1042", "customer": "Acme Inc.", "total": 49.00},
})
req, _ := http.NewRequest("POST", "https://api.pdfmakerapi.com/v1/render", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PDF_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
out, _ := os.Create("invoice.pdf")
io.Copy(out, res.Body)

Same JSON, same endpoint, five languages. The PDF comes back in the response body.

Where the template comes from

You don't write HTML. You design the template in a visual, drag-and-drop editor — drop in text, tables, images, and {{variables}} — or describe it in plain English and let the AI build it. Change the design later without touching your code; your request body stays the same.

And because it renders from a structured template (not a screenshot of a webpage), layouts don't break when the data changes — and there's no headless browser, so it generates thousands of PDFs in seconds.

Generating in bulk

It's just HTTP, so loop your data:

for inv in invoices:
    pdf = requests.post(URL, headers=H, json={
        "template_id": "invoice_default", "data": inv,
    }).content
    open(f"{inv['number']}.pdf", "wb").write(pdf)

Try it

PDFMakerAPI is free to start — 100 PDFs/month, no card. Design a template, grab an API key, and you're rendering PDFs from any language in a few minutes. You can also generate from no-code tools (Zapier, Make, n8n) or straight from AI agents (Claude, ChatGPT) — same templates, same output.

What's the worst PDF-generation setup you've had to maintain? Curious what people are running.