<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Toan Huynh</title>
    <description>The latest articles on Forem by Toan Huynh (@khanhtoandng).</description>
    <link>https://forem.com/khanhtoandng</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F741156%2F77c4de86-0aca-4e01-9a9d-8428f30fd5a8.jpeg</url>
      <title>Forem: Toan Huynh</title>
      <link>https://forem.com/khanhtoandng</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/khanhtoandng"/>
    <language>en</language>
    <item>
      <title>Automating Authentication in Apollo Sandbox Explorer with Pre-request Scripts</title>
      <dc:creator>Toan Huynh</dc:creator>
      <pubDate>Thu, 17 Oct 2024 03:51:33 +0000</pubDate>
      <link>https://forem.com/khanhtoandng/automating-authentication-in-apollo-sandbox-explorer-with-pre-request-scripts-1fil</link>
      <guid>https://forem.com/khanhtoandng/automating-authentication-in-apollo-sandbox-explorer-with-pre-request-scripts-1fil</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Apollo Sandbox provides a powerful feature that allows developers to add JavaScript-based scripts to enhance the functionality of their GraphQL requests. These scripts come in two flavors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Preflight scripts&lt;/strong&gt;: Execute before every operation, making them ideal for managing authentication flows (e.g., refreshing expired access tokens).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Postflight scripts&lt;/strong&gt;: Run after the operation completes, useful for validating workflows that depend on response data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi110lw384kj0se3brfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi110lw384kj0se3brfe.png" alt="Execution Order of Scripts" width="800" height="82"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Preflight Script
&lt;/h2&gt;

&lt;p&gt;Follow these steps to add a preflight script that automatically refreshes your access token:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Apollo Sandbox and nagivate to the &lt;code&gt;Explorer&lt;/code&gt; tab in the sidebar.&lt;/li&gt;
&lt;li&gt;Access the &lt;code&gt;Explorer’s Setting&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;Preflight Script&lt;/code&gt; section, click &lt;code&gt;Add script&lt;/code&gt; button. A script editor dialog will appears.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wsmtqckyxjf96c0eqbh.png" alt="Sidebar" width="800" height="492"&gt;
&lt;/li&gt;
&lt;li&gt;Enter your JavaScript code in the &lt;code&gt;Script Editor&lt;/code&gt; panel. An example script that refreshes an access token is &lt;a href="https://gist.github.com/khanhtoandng/5d89d5f2bec5ce8921639306fbd35d51" rel="noopener noreferrer"&gt;here&lt;/a&gt;.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0tfff2p3cvjzdm1mk8da.png" alt="Preflight Script Editor" width="800" height="570"&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Save&lt;/code&gt; to store your script. You can use the &lt;code&gt;Test Script&lt;/code&gt; button to debug its execution.&lt;/li&gt;
&lt;li&gt;Scroll down to the Scripts section in Explorer's Settings to verify that the Preflight script is turned ON.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjn8m3tlbznv5t3tea55y.png" alt="Preflight scripts Config" width="800" height="318"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Using Environment Variables in Headers
&lt;/h2&gt;

&lt;p&gt;To use access token in requests:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;code&gt;Headers&lt;/code&gt; tab in Explorer.&lt;/li&gt;
&lt;li&gt;Add an &lt;code&gt;authorization&lt;/code&gt; header and set its value using the environment variable syntax: &lt;code&gt;{{accessToken}}&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your header should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3hyrv3g9sktwkrgxe90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3hyrv3g9sktwkrgxe90.png" alt="Explorer Header" width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;By implementing preflight scripts in Apollo Sandbox Explorer, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automate token refresh, eliminating the need for manual re-authentication when access tokens expire.&lt;/li&gt;
&lt;li&gt;Streamline your development process by automating common tasks and setting variables dynamically.&lt;/li&gt;
&lt;li&gt;Enhance the efficiency and security of your GraphQL API testing workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Preflight scripts are a powerful tool that can significantly improve your experience when working with Apollo Sandbox Explorer. Give it a try and see how it can benefit your development process!&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/docs/graphos/platform/explorer/scripting" rel="noopener noreferrer"&gt;https://www.apollographql.com/docs/graphos/platform/explorer/scripting&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>graphql</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Deploy Puppeteer and Chrome on AWS Lambda With Layers and AWS CDK</title>
      <dc:creator>Toan Huynh</dc:creator>
      <pubDate>Wed, 04 Sep 2024 09:11:41 +0000</pubDate>
      <link>https://forem.com/khanhtoandng/deploy-puppeteer-and-chrome-on-aws-lambda-with-layers-and-aws-cdk-13bo</link>
      <guid>https://forem.com/khanhtoandng/deploy-puppeteer-and-chrome-on-aws-lambda-with-layers-and-aws-cdk-13bo</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In this blog post, we’ll show how to create a Lambda function that generates PDF file from HTML using Puppeteer and uploads PDF to S3.&lt;/li&gt;
&lt;li&gt;We’ll also explore how to deploy Chromium on AWS Lambda Layer.&lt;/li&gt;
&lt;li&gt;This blog post uses the &lt;a href="https://docs.aws.amazon.com/cdk/" rel="noopener noreferrer"&gt;The AWS Cloud Development Kit&lt;/a&gt; (AWS CDK) and &lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;AWS Command Line Interface&lt;/a&gt; (AWS CLI) to simplify the deployment of AWS resources.&lt;/li&gt;
&lt;li&gt;You can download the code for this blog post from the &lt;a href="https://github.com/khanhtoandng/cdk-typescript-lambda-chromium" rel="noopener noreferrer"&gt;Github Repository&lt;/a&gt;. To deploy to your AWS account, follow the instructions in the README file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;In this post, a client sends a request to a Lambda function that generates PDF and saves it to an S3 bucket. The architecture looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiidi5a1msduqex5mruk3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiidi5a1msduqex5mruk3.png" alt="Application architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account with appropriate permissions.&lt;/li&gt;
&lt;li&gt;AWS CLI - check out &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html#cli-configure-files-methods" rel="noopener noreferrer"&gt;AWS Document&lt;/a&gt; to install and configure credentials.&lt;/li&gt;
&lt;li&gt;AWS CDK v2 - Install &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_install" rel="noopener noreferrer"&gt;AWS CDK CLI&lt;/a&gt; globally.&lt;/li&gt;
&lt;li&gt;Node.js 18+ and NPM - &lt;a href="https://nodejs.org/en/download/package-manager" rel="noopener noreferrer"&gt;Download Link&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Initialize the Project with AWS CDK in Typescript
&lt;/h2&gt;

&lt;p&gt;Run this command to create a folder and navigate into the directory for our app:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir cdk-typescript-lambda-chromium &amp;amp;&amp;amp; cd cdk-typescript-lambda-chromium
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, initialize a blank AWS CDK project in Typescript by running the command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk init app --language typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will generate a project structure with various directories, files and dependencies required. Below is the project structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotsaez2k6xdzj1b4ptf9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotsaez2k6xdzj1b4ptf9.png" alt="Project structure created by the AWS CDK CLI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the project structure, there are a few main files to focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cdk.json&lt;/code&gt;: Contains information that the toolkit will use to run our app. In our case, it will be &lt;code&gt;npx ts-node --prefer-ts-exts bin/cdk-typescript-lambda-chromium.ts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bin/cdk-typescript-lambda-chromium.ts&lt;/code&gt;: The entry point of the CDK application. It loads whatever the stack we define in &lt;code&gt;lib/cdk-typescript-lambda-chromium-stack.ts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lib/cdk-typescript-lambda-chromium-stack.ts&lt;/code&gt;: This is where the CDK application's main stack is defined. We'll spend most of our time here to create Lambda Function.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create S3 bucket
&lt;/h2&gt;

&lt;p&gt;First, we’ll create a new S3 bucket to store Chromium Layer and generated PDF files with CLI command below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws s3 mb s3://YOUR_S3_BUCKET_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Setting up Puppeteer and Chrome on AWS Lambda
&lt;/h2&gt;

&lt;p&gt;Next, we’ll need to use &lt;code&gt;puppeteer-core&lt;/code&gt;, which includes only a compressed version of Chrome. To incorporate Puppeteer into AWS Lambda function, we'll utilize the &lt;code&gt;chromium&lt;/code&gt; package, packages by &lt;a href="https://github.com/Sparticuz/chromium" rel="noopener noreferrer"&gt;Sparticuz - Github&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This package will be bundled into Lambda Layer, a convenient way to reuse code across multiple Lambda functions. It increases performance compared to using the off-the-shelf &lt;code&gt;puppeteer&lt;/code&gt; bundle and decrease bundle size, leading to potentially faster deployment times.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use the following commands to create a zipped Chromium layer with Linux commands:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone --depth=1 https://github.com/sparticuz/chromium.git &amp;amp;&amp;amp; \
    cd chromium &amp;amp;&amp;amp; \
    make chromium.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will create a &lt;code&gt;chromium.zip&lt;/code&gt; file. Uploading it to the S3 bucket to easy addition to the Lambda Layer and to store it for future use via AWS CLI:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bucketName="YOUR_S3_BUCKET_NAME" &amp;amp;&amp;amp; \
versionNumber="127" &amp;amp;&amp;amp; \
aws s3 cp chromium.zip "s3://${bucketName}/chromiumLayers/chromium${versionNumber}.zip" &amp;amp;&amp;amp; \
aws lambda publish-layer-version --layer-name chromium --description "Chromium v${versionNumber}" --content "S3Bucket=${bucketName},S3Key=chromiumLayers/chromium${versionNumber}.zip" --compatible-runtimes nodejs --compatible-architectures x86_64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When the command runs successfully, the output will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpu45aq6isoldca5kyacf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpu45aq6isoldca5kyacf.png" alt="Output for creating lambda layer successfully"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Lambda Function Stack with AWS CDK
&lt;/h2&gt;

&lt;p&gt;Then, we’ll define our CDK stack, which will contain the AWS resources required for PDF generating function.&lt;/p&gt;

&lt;p&gt;Before that, we’ll install a package called &lt;code&gt;dotenv&lt;/code&gt; and create a &lt;code&gt;config.ts&lt;/code&gt; file in &lt;code&gt;lib&lt;/code&gt; to load environment variables from &lt;code&gt;.env&lt;/code&gt; file. Install the package using:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install dotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We'll use the AWS CDK to define the infrastructure as code. The &lt;a href="https://github.com/khanhtoandng/cdk-typescript-lambda-chromium/blob/main/lib/cdk-typescript-lambda-chromium-stack.ts" rel="noopener noreferrer"&gt;AWS CDK Stack&lt;/a&gt; defines all the AWS resources used by the application. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AWS CDK helps create repeatable deployments quickly and reduces human error from clicking around the console.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, fetch Chromium Lambda Layer ARN:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const chromiumLayer = lambda.LayerVersion.fromLayerVersionArn(
      this,
      'chromiumLayerStack',
      config.getChromiumLayerArn()
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, we’ll define the Lambda function that runs on Node.js 18 with 1GB of memory allocated. The &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;handler&lt;/code&gt; properties indicate where the code is located. The timeout is set to 300 seconds(5 minutes). This stack also includes a reference to the Chromium layer that is needed inside our Lambda, and the region code at deployment time:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const lambdaFunction = new lambda.Function(this, 'lambdaNodeStack', {
      code: lambda.Code.fromAsset('src/generating-pdf/lib'),
      functionName: `generatingPdfLambda`,
      handler: 'index.handler',
      memorySize: 1024,
      runtime: lambda.Runtime.NODEJS_18_X,
      description: 'Convert html to PDF for users to download',
      environment: {
        REGION: config.getRegion(),
      },
      timeout: cdk.Duration.seconds(300),
      layers: [chromiumLayer],
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Since our lambda function needs to read and write data to S3, we'll grant the necessary permissions to access the S3 Bucket. This follows the &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege" rel="noopener noreferrer"&gt;principle of least privilege&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const bucketArn = config.getS3BucketArn()

lambdaFunction.addToRolePolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ['s3:GetObject', 's3:PutObject'],
        resources: [bucketArn, `${bucketArn}/*`],
      })
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally, we create a Lambda URL endpoint by calling the &lt;code&gt;addFunctionUrl()&lt;/code&gt; method on our Lambda Function instance. We pass in two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;authType&lt;/strong&gt;: The authentication mode required to invoke the Lambda function; we use &lt;code&gt;FunctionUrlAuthType.NONE&lt;/code&gt; to make the Lambda publicly accessible, so anyone with the Function URL can invoke it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cors:&lt;/strong&gt; We set it to ['*'] to allow all domains.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const myFunctionUrl = lambdaFunction.addFunctionUrl({
      authType: lambda.FunctionUrlAuthType.NONE,
      cors: {
        allowedOrigins: ['*'],
      },
    })

new cdk.CfnOutput(this, 'LambdaNodeUrl', {
      value: myFunctionUrl.url,
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Define the Lambda Function Code
&lt;/h2&gt;

&lt;p&gt;In the project structure, we’ll create a folder called &lt;code&gt;src/generating-pdf&lt;/code&gt; to store all function code with Node.js runtime.&lt;/p&gt;

&lt;p&gt;The entire Lambda function code can be found &lt;a href="https://github.com/khanhtoandng/cdk-typescript-lambda-chromium/blob/main/src/generating-pdf/src/index.ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The main code for generating PDF is:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.....

// Launch a headless Chrome browser using puppeteer
const browser = await puppeteer.launch({
  args: chromium.args,
  defaultViewport: chromium.defaultViewport,
  executablePath: await chromium.executablePath(),
  headless: chromium.headless
})

// Open a new page in the browser
const page = await browser.newPage()

// Set html content on the new page
await page.setContent(requestBody.html)

// Generate PDF
const buffer = await page.pdf({
  format: 'A4',
  margin: { bottom: '50px', top: '50px', left: '50px', right: '50px' },
})

// Close the page and browser
await page.close()
await browser.close()

// Upload the PDF to the S3 bucket
await s3Client.send(new PutObjectCommand({
  Bucket: bucketName,
  Key: `${new Date().getTime()}`,
  Body: buffer,
  ContentType: 'application/pdf',
}))

.....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A file with these dependencies would be:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"dependencies": {
  "@aws-sdk/client-s3": "^3.637.0",
  "@aws-sdk/s3-request-presigner": "^3.637.0",
  "puppeteer-core": "^23.2.0"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Deploy the Lambda Function on AWS
&lt;/h2&gt;

&lt;p&gt;First, run the &lt;code&gt;cdk synth&lt;/code&gt; command, which generates the CloudFormation template from the AWS CDK code. This command will also validate the stack definition and raise an error if there are any issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ghxmviljtg7vy58bz88.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ghxmviljtg7vy58bz88.png" alt="Generating CloudFormation template from CDK"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, run &lt;code&gt;cdk bootstrap&lt;/code&gt; to create a CloudFormation stack that includes the necessary resources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxpi7lmv5i6m4bgb1txc4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxpi7lmv5i6m4bgb1txc4.png" alt="Creating CloudFormation Stack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, deploy our project with the &lt;code&gt;cdk deploy&lt;/code&gt; command. After running this command, we'll see the output below. Press &lt;strong&gt;&lt;code&gt;y&lt;/code&gt;&lt;/strong&gt; to continue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hm4zuwpf6061oedzdzw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hm4zuwpf6061oedzdzw.png" alt="Deploying CDK Stack to AWS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the deployment completes, we'll receive the Lambda function's URL in the output, which you can invoke to generate PDFs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb7ks5ehi7v4juw3m382l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb7ks5ehi7v4juw3m382l.png" alt="Successful deployment output"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Test the Lambda Function with the Function URL
&lt;/h2&gt;

&lt;p&gt;To test the function, we'll simply send a POST request to the Lambda function URL with an HTML string, like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location 'LAMBDA_FUNCTION_URL' \
--header 'Content-Type: application/json' \
--data '{
  "html": "&amp;lt;h1&amp;gt;HELLO WORLD: THIS IS GENERATING PDF LAMBDA&amp;lt;/h1&amp;gt;\n&amp;lt;p&amp;gt;&amp;lt;img src=\"https://cdn.britannica.com/77/234477-050-DF90E2ED/Doberman-pinscher-dog.jpg\" alt=\"\" width=\"691\" height=\"496\"&amp;gt;&amp;lt;/p&amp;gt;"
}
'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This should generate a PDF from the provided HTML and return the S3 bucket URL where the PDF was saved.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk48pk0vpreqo99y47tg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk48pk0vpreqo99y47tg7.png" alt="Generated PDF File from HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog post, we walked through deploying a Lambda function with Puppeteer and Chromium for PDF generation and explored setting up AWS resources using AWS CDK. This is a scalable solution to generate PDFs in the cloud.&lt;/p&gt;

&lt;p&gt;I hope this post helpful to you and thank you for reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/aws-samples/cdk-typescript-lambda/tree/main" rel="noopener noreferrer"&gt;https://github.com/aws-samples/cdk-typescript-lambda/tree/main&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.tericcabrel.com/create-lambda-function-with-node-js-and-typescript-on-aws-cdk/" rel="noopener noreferrer"&gt;https://blog.tericcabrel.com/create-lambda-function-with-node-js-and-typescript-on-aws-cdk/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Sparticuz/chromium" rel="noopener noreferrer"&gt;https://github.com/Sparticuz/chromium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pluralsight.com/resources/blog/cloud/serverless-browser-automation-with-aws-lambda-and-puppeteer" rel="noopener noreferrer"&gt;https://www.pluralsight.com/resources/blog/cloud/serverless-browser-automation-with-aws-lambda-and-puppeteer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>cdk</category>
      <category>node</category>
    </item>
  </channel>
</rss>
