Generare pdf con aws lambda
Franco Berton - May 20, 2021
Questo articolo spiega come generare un file pdf con aws lambda in NodeJs utilizzando la libreria puppeteer.
Index
- 1. Definizione microservizio nel file serverless
- 2. Creazione lambda function
- 3. Inclusione nel bundle dei file binari di chromium
- 4. Risultato
- 5. Conclusioni
Introduzione: Questo articolo vuole essere una guida introduttiva su come generare un pdf con AWS Lambda in Node Js con la libreria Puppeteer.
Pre-requisiti: La seguente guida ha come prerequisito l'integrazione dei seguenti moduli:
- serverless: framework volto alla creazione di applicazioni composte da microservizi e facilitare la distribuzione all'interno della piattaforma AWS;
- serverless-bundle: plugin che impacchetta in modo ottimale le Lambda functions definite con ES6 o TypeScript basandosi sul plugin interno serverless-webpack;
- serverless-offline: plugin per emulare AWS e Api Gateway sulla macchina locale per accelerare i cicli di sviluppo;
- puppeteer-serverless, plugin fondamentale per la generazione del pdf con AWS Lambda. Internamente include come dipendenze: chrome-aws-lambda e puppeteer-core
Le dipendenze del nostro package.json si presenteranno in questo modo:
"dependencies": {
"puppeteer-serverless": "^2.0.0"
},
"devDependencies": {
"serverless": "^2.11.1",
"serverless-bundle": "^4.0.1",
"serverless-offline": "^6.8.0",
"typescript": "^3.9.7"
}
1. Definizione microservizio nel file serverless
Il primo passo per la generazione di un pdf con AWS Lambda in NodeJs prevede la definizione di un microservizio all'interno del file serverless, il quale contiene la configurazione per il deployment.
Il microservizio sarà raggiungigibile all'esterno con una semplice api di get. Di seguito la definizione del file serverless:
service: pdf
plugins:
- serverless-bundle
- serverless-offline
package:
individually: true
custom:
serverless-offline:
location: .webpack/service
bundle:
sourcemaps: false
provider:
name: aws
runtime: nodejs12.x
region: eu-central-1
stage: test
apiGateway:
shouldStartNameWithService: true
binaryMediaTypes:
- '*/*'
tracing:
apiGateway: true
lambda: true
functions:
downloadPdf:
handler: lambdas/download-pdf.main
events:
- http:
path: download-pdf
method: get
cors: true
timeout: 180
2. Creazione della lambda function
A questo punto è necessario definire una lambda function per effettuare la magia. Il processo di generazione del pdf prevede:
- definizione contenuto html da stampare;
- caricamento e apertura del file html con puppeteer;
- generazione del file pdf con puppeteer;
- conversione del contenuto in base64.
import puppeteer from "puppeteer-serverless";
export const main = async (event: any, context: any): Promise<any> => {
let browser = null;
let pdf = null;
try {
browser = await puppeteer.launch({});
const page = await browser.newPage();
await page.setContent("<html><body><p>Test</p></body></html>", {
waitUntil: "load",
});
pdf = await page.pdf({
format: "A4",
printBackground: true,
displayHeaderFooter: true,
margin: {
top: 40,
right: 0,
bottom: 40,
left: 0,
},
headerTemplate: `
<div style="border-bottom: solid 1px gray; width: 100%; font-size: 11px;
padding: 5px 5px 0; color: gray; position: relative;">
</div>`,
footerTemplate: `
<div style="border-top: solid 1px gray; width: 100%; font-size: 11px;
padding: 5px 5px 0; color: gray; position: relative;">
<div style="position: absolute; right: 20px; top: 2px;">
<span class="pageNumber"></span>/<span class="totalPages"></span>
</div>
</div>
`,
});
} finally {
if (browser !== null) {
await browser.close();
}
}
return {
headers: {
'Content-type': 'application/pdf',
'content-disposition': 'attachment; filename=test.pdf'
},
statusCode: 200,
body: pdf.toString('base64'),
isBase64Encoded: true
}
}
3. Inclusione nel bundle dei file binari di chromium
Come ultimo step andiamo ad aggiornare il file serverless con l'inclusione dei file binari di chromium nel bundle, affinchè il download del pdf possa funzionare su AWS
I file binari sono presenti all'interno del modulo chrome-aws-lambda e quindi, saranno:
- node_modules/chrome-aws-lambda/bin/aws.tar.br
- node_modules/chrome-aws-lambda/bin/chromium.br
- node_modules/chrome-aws-lambda/bin/swiftshader.tar.br
service: pdf
plugins:
- serverless-bundle
- serverless-offline
package:
individually: true
custom:
serverless-offline:
location: .webpack/service
bundle:
sourcemaps: false
copyFiles:
- from: 'node_modules/chrome-aws-lambda/bin/aws.tar.br'
to: './bin'
- from: 'node_modules/chrome-aws-lambda/bin/chromium.br'
to: './bin'
- from: 'node_modules/chrome-aws-lambda/bin/swiftshader.tar.br'
to: './bin'
provider:
name: aws
runtime: nodejs12.x
region: eu-central-1
stage: test
apiGateway:
shouldStartNameWithService: true
binaryMediaTypes:
- '*/*'
tracing:
apiGateway: true
lambda: true
functions:
downloadPdf:
handler: lambdas/download-pdf.main
events:
- http:
path: download-pdf
method: get
cors: true
timeout: 180
4. Risultato
5. Conclusioni
La soluzione proposta evidenzia la semplicità e l'immediatezza per la generazione di un pdf con AWS lambda.
In alternativa a questo approccio, si può utilizzare il plugin PDFkit, ma la considero una strada più complessa e dispendiosa.
Il codice della soluzione proposta è visualizzabile in questo repository Github.
Se vi è un piaciuto il mio articolo, vi invito a condividerlo.
Il vostro supporto e feedback significa molto per noi.