Business: root cause found (CSP blocks inline JS), Playwright for QA, updated bug tracker
This commit is contained in:
parent
d498a1bffa
commit
0cefaf71d1
7 changed files with 514 additions and 80 deletions
203
projects/business/memory/devto-draft.md
Normal file
203
projects/business/memory/devto-draft.md
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
---
|
||||
title: "Stop Wrestling with Puppeteer: Generate PDFs with One API Call"
|
||||
published: false
|
||||
description: "How to generate invoices, reports, and documents as PDFs from HTML, Markdown, or JSON data — without managing headless browsers."
|
||||
tags: webdev, api, node, tutorial
|
||||
cover_image: # (add a cover image URL)
|
||||
---
|
||||
|
||||
Every developer has the same PDF story. It starts innocently:
|
||||
|
||||
> "Can we add a 'Download as PDF' button?"
|
||||
|
||||
Three days later, you're debugging Chrome memory leaks in production, your Puppeteer instance is eating 2GB of RAM, and the PDFs look different on every server.
|
||||
|
||||
I got tired of this cycle, so I built [DocFast](https://docfast.dev) — a PDF API that takes HTML, Markdown, or structured data and returns a PDF. No headless browser setup, no dependencies.
|
||||
|
||||
Here's what I learned, and how you can generate PDFs in about 30 seconds.
|
||||
|
||||
## The Simple Version
|
||||
|
||||
```bash
|
||||
curl -X POST https://docfast.dev/v1/convert/html \
|
||||
-H "Authorization: Bearer YOUR_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"html": "<h1>Hello World</h1><p>This is a PDF.</p>"}' \
|
||||
-o hello.pdf
|
||||
```
|
||||
|
||||
That's it. JSON in, PDF out.
|
||||
|
||||
## Three Ways to Generate PDFs
|
||||
|
||||
DocFast has three conversion endpoints, each for a different use case:
|
||||
|
||||
### 1. HTML → PDF
|
||||
|
||||
You have full control. Pass any HTML with optional CSS:
|
||||
|
||||
```javascript
|
||||
const response = await fetch('https://docfast.dev/v1/convert/html', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer YOUR_KEY',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
html: `
|
||||
<h1 style="color: navy;">Monthly Report</h1>
|
||||
<p>Revenue: <strong>$12,345</strong></p>
|
||||
<table>
|
||||
<tr><td>Users</td><td>1,234</td></tr>
|
||||
<tr><td>MRR</td><td>$5,670</td></tr>
|
||||
</table>
|
||||
`,
|
||||
css: 'body { font-family: Georgia, serif; padding: 40px; }',
|
||||
format: 'A4'
|
||||
})
|
||||
});
|
||||
|
||||
const pdf = await response.arrayBuffer();
|
||||
fs.writeFileSync('report.pdf', Buffer.from(pdf));
|
||||
```
|
||||
|
||||
### 2. Markdown → PDF
|
||||
|
||||
This is my favorite endpoint. Write Markdown, get a styled PDF with syntax highlighting:
|
||||
|
||||
```javascript
|
||||
const markdown = `
|
||||
# Project Proposal
|
||||
|
||||
## Overview
|
||||
We propose building a **real-time dashboard** for monitoring API usage.
|
||||
|
||||
## Timeline
|
||||
| Phase | Duration | Cost |
|
||||
|-------|----------|------|
|
||||
| Design | 2 weeks | $3,000 |
|
||||
| Build | 4 weeks | $8,000 |
|
||||
| Test | 1 week | $1,500 |
|
||||
|
||||
## Code Sample
|
||||
\`\`\`javascript
|
||||
const analytics = new Analytics({ key: 'abc123' });
|
||||
analytics.track('pdf_generated', { format: 'A4' });
|
||||
\`\`\`
|
||||
`;
|
||||
|
||||
const response = await fetch('https://docfast.dev/v1/convert/markdown', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer YOUR_KEY',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ markdown })
|
||||
});
|
||||
```
|
||||
|
||||
Tables, code blocks, images — it all renders beautifully.
|
||||
|
||||
### 3. URL → PDF
|
||||
|
||||
Need to snapshot a webpage? Just pass the URL:
|
||||
|
||||
```bash
|
||||
curl -X POST https://docfast.dev/v1/convert/url \
|
||||
-H "Authorization: Bearer YOUR_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"url": "https://example.com", "waitUntil": "networkidle0"}' \
|
||||
-o page.pdf
|
||||
```
|
||||
|
||||
It handles JavaScript-rendered pages too (SPAs, dashboards, etc).
|
||||
|
||||
## The Killer Feature: Invoice Templates
|
||||
|
||||
This is what I wish existed years ago. Instead of building invoice HTML from scratch, you pass JSON data and get a professional invoice:
|
||||
|
||||
```javascript
|
||||
const response = await fetch('https://docfast.dev/v1/templates/invoice/render', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer YOUR_KEY',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
data: {
|
||||
invoiceNumber: 'INV-2026-042',
|
||||
date: '2026-02-14',
|
||||
dueDate: '2026-03-14',
|
||||
from: {
|
||||
name: 'Your Company',
|
||||
address: '123 Main St',
|
||||
email: 'billing@yourco.com'
|
||||
},
|
||||
to: {
|
||||
name: 'Client Corp',
|
||||
address: '456 Oak Ave',
|
||||
email: 'ap@client.com'
|
||||
},
|
||||
items: [
|
||||
{ description: 'Web Development', quantity: 40, unitPrice: 95, taxRate: 20 },
|
||||
{ description: 'Hosting', quantity: 1, unitPrice: 29 }
|
||||
],
|
||||
currency: '€',
|
||||
notes: 'Payment due within 30 days.',
|
||||
paymentDetails: 'IBAN: AT12 3456 7890 1234 5678'
|
||||
}
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
No HTML. No CSS. Just data → PDF.
|
||||
|
||||
## Integrating Into Your App
|
||||
|
||||
Here's a minimal Express.js endpoint that generates and returns an invoice:
|
||||
|
||||
```javascript
|
||||
app.get('/api/invoice/:id', async (req, res) => {
|
||||
const invoice = await db.getInvoice(req.params.id);
|
||||
|
||||
const pdfResponse = await fetch('https://docfast.dev/v1/templates/invoice/render', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.DOCFAST_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ data: invoice })
|
||||
});
|
||||
|
||||
res.setHeader('Content-Type', 'application/pdf');
|
||||
res.setHeader('Content-Disposition', `attachment; filename=invoice-${invoice.invoiceNumber}.pdf`);
|
||||
pdfResponse.body.pipe(res);
|
||||
});
|
||||
```
|
||||
|
||||
12 lines. Your users can download invoices.
|
||||
|
||||
## Why Not Just Use Puppeteer?
|
||||
|
||||
You can! But here's what you're signing up for:
|
||||
|
||||
- **Memory:** Each Chrome instance uses 200-500MB RAM
|
||||
- **Cold starts:** Launching a browser takes 1-3 seconds
|
||||
- **Stability:** Chrome crashes, zombie processes, OOM kills
|
||||
- **DevOps:** Managing Chrome versions, fonts, dependencies in Docker
|
||||
- **Concurrency:** Need multiple PDFs at once? Now you're managing a browser pool
|
||||
|
||||
DocFast handles all of this. Persistent browser pool, sub-second generation, no infrastructure to manage.
|
||||
|
||||
## Pricing
|
||||
|
||||
- **Free:** 100 PDFs/month, all endpoints, all templates
|
||||
- **Pro:** $9/month for 10,000 PDFs/month
|
||||
|
||||
No per-page fees. No credit card for the free tier. [Get your API key here](https://docfast.dev).
|
||||
|
||||
---
|
||||
|
||||
If you have questions about the API or want to see specific templates added, drop a comment. I'm actively building based on user feedback.
|
||||
|
||||
Happy PDF-ing! 📄
|
||||
Loading…
Add table
Add a link
Reference in a new issue