Skip to main content

Setup

To get started with the PDF Generator Pod in your project, follow the below mentioned steps.

cd my_project
./node_modules/.bin/nest g lib pdf-worker # answer the question whatever is asked for.
torque add-pod pdf-generator --directory libs/pdf-worker --latest

You should see an output like below.

tip

It is highly recommended to keep PDF Generator function outside your main backend application, as this is heavy and needs good amount of computing power.

A good idea will be to keep all serverless applications as a separate project.

Configuration

Use ConfigModule provided by NestJS to load configurations. To learn about ConfigModule, click here.

1. Create config/pdf-worker.ts

import { registerAs } from '@nestjs/config';

const defaultMargin = {
top: '10px',
right: '10px',
bottom: '10px',
left: '10px',
};

export default registerAs('pdf', () => ({
moduleSettings: {
default: 'docs',
isLocal: process.env.NODE_ENV === 'local',
variants: {
docs: {
pdfOption: {
landscape: false, // <-- must be set to true to get a landscape PDF
format: 'legal',
margin: defaultMargin,
printBackground: true, // required for photos otherwise blank
scale: 1,
},
compress: true,
},
},
},
variants: ['docs'],
}));

2. Register Async PdfWorkerModule Add following snippet to the imports array. ConfigService is importable from @nestjs/config module

PdfWorkerModule.registerAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => config.get('pdf.moduleSettings'),
inject: [ConfigService],
}),

Usage

Now that the configuration and setup is complete, let's see how we can use it.

The usage is pretty straight forward, the module exports a PDFWorkerService class which you can use to either, generate OR compress the pdf.

TaskMethodName
Generate PDF from HTMLgenerateFromHtml
Compress PDFcompress

Generating PDF

services/pdf.ts

import { Injectable } from '@nestjs/common';
import { GeneratePdfDto, PDFWorkerService } from '@squareboat/pdf-worker';

@Injectable()
export class PdfService {
constructor(private lib: PDFWorkerService) {}

async generatePdf(inputs: GeneratePdfDto): Promise<Record<string, any>> {
const pdfBuffer = await this.lib.generateFromHtml(inputs);
// write your logic for saving the pdf buffer for saving to s3 or any disk here.
return {};
}
}

You can use this PDFService further in your controller and start using the API for generating the PDF.

controllers/pdf.ts

@Controller()
export class PdfWorkerController {
constructor(
private readonly service: PdfService,
private readonly validator: BaseValidator,
) {}

@Post('generate')
async generatePdf(
@Req() req: Request,
@Res() res: Response,
): Promise<Response> {
const dto = await this.validator.fire(req.all(), GeneratePdfDto);
const pdfData = await this.service.generatePdf(dto);
return res.success({
pdfData,
msg: 'PDF Generated successfully',
});
}
}

You can test your integration by sending a sample request to your controller, as below.

# URL
{{base_url}}/pdf-worker/generate

# Body
{
"sourceDisk": "html",
"html": "<!DOCTYPE html>\n<html>\n<body>\n\n<p>I am normal</p>\n<p style=\"color:red;\">I am red</p>\n<p style=\"color:blue;\">I am blue</p>\n<p style=\"font-size:50px;\">I am big</p>\n\n</body>\n</html>\n\n",
"destination": {
"bucket": "batteries-test",
"path": "docs/resume.pdf"
},
"compress": true,
"pdfVariant": "docs"
}

Postman Collection

API

1. GeneratePdfDto

export class GeneratePdfDto {
@IsIn(["html", "s3"])
sourceDisk!: "html" | "s3";

@IsString()
@ValidateIf((o) => o.sourceDisk === "html")
@IsNotEmpty()
html!: string;

@ValidateNested()
@IsNotEmpty()
@ValidateIf((o) => o.sourceDisk === "s3")
@Type(() => S3ConfigDto)
s3!: S3ConfigDto;

@IsOptional()
@ValidateIf((o) => o.sourceDisk === "s3")
htmlInputs!: Record<string, any>;

@IsBoolean()
@IsNotEmpty()
compress = true;

@ValidateNested()
@IsNotEmpty()
@Type(() => S3ConfigDto)
destination!: S3ConfigDto;

@IsString()
pdfVariant!: string;
}

2. S3ConfigDto

export class S3ConfigDto {
@IsNotEmpty()
@IsString()
bucket!: string;

@IsNotEmpty()
@IsString()
path!: string;
}