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.
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.
Task | MethodName |
---|---|
Generate PDF from HTML | generateFromHtml |
Compress PDF | compress |
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"
}
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;
}