Tailwind Logo

Interacting with Next.js API and Playwright's Container (Part 3)

Next.jsRelated Technology

Published: 2023-10-26

This is the final installment in this series. Now that we have reached the point of taking screenshots, we will link them to storage. This time, we will finish up the integration with Azure Blob Storage.

Preparation for Azure Blob Storage Linkage

This time, we will implement placing the acquired thumbnail image in Azure Blob Storage, and if that image is available, the screenshot process will not be executed. We will omit the creation of the storage this time.

First, install the @azure/storage-blob module so that Azure Blob Storage can be used in the sample you are currently creating.

PowerShell
npm install -D @azure/storage-blob

Then add the following code to the previous file

TypeScript
import {
  BlobServiceClient,
  StorageSharedKeyCredential,
} from "@azure/storage-blob";

Then, to keep the values as environment variables, the following entries are added to the .env file to set the storage account, access key and container values.

Plain Text
AZURE_STORAGE_ACCOUNT=
AZURE_STORAGE_ACCESS_KEY=
AZURE_STORAGE_CONTAINER=

The following code should be added so that the above values can be read in programmatically.

TypeScript
  const AZURE_STORAGE_ACCOUNT = process.env["AZURE_STORAGE_ACCOUNT"] || "";
  const AZURE_STORAGE_ACCESS_KEY = process.env["AZURE_STORAGE_ACCESS_KEY"] || "";
  const AZURE_STORAGE_CONTAINER = process.env["AZURE_STORAGE_CONTAINER"]  || "";

The preparation is now complete.

Upload to Azure Blob Storage

The part that uploads acquired images each time is created first. First, the procedure for connecting to Azure Blob Storage is described below.

TypeScript
  const sharedKeyCredential = new StorageSharedKeyCredential(
    AZURE_STORAGE_ACCOUNT,
    AZURE_STORAGE_ACCESS_KEY
  );
  const blobServiceClient = new BlobServiceClient(
    `https://${AZURE_STORAGE_ACCOUNT}.blob.core.windows.net`,
    sharedKeyCredential
  );
  const containerClient = blobServiceClient.getContainerClient(
    AZURE_STORAGE_CONTAINER
  );

The code was then rewritten to upload the acquired images as follows

TypeScript
  try {
    const externalApiUrl =
      NEXT_PUBLIC_PLAYWRIGHT + "/api/screenshot?url=" + url;
    const response = await axios.get(externalApiUrl);
    const imageData = response.data.screenshot;
    const decodedImageData = Buffer.from(imageData, "base64");

    const blockBlobClient = containerClient.getBlockBlobClient(
      domain + "/" + filename + ".png"
    );
    await blockBlobClient.uploadData(decodedImageData);
    console.log("Image was uploaded");

    res.setHeader("Content-Type", "image/png");
    res.status(200).end(decodedImageData, "binary");
  } catch (error) {
    return res.status(500).json({ error: "Can't get content data" });
  }

This took the form of creating a screenshot using the URL obtained by the API, saving the file to storage, and rewriting it to display the image.

In fact, we passed some URLs and were able to confirm that the files were generated as follows.

playwright26.png

Check for file availability

For URLs that have already been retrieved, add a check to see if the file exists. The rewritten code is as follows

TypeScript
  try {
    const blockBlobClient = containerClient.getBlockBlobClient(
      domain + "/" + filename + ".png"
    );
    const exists = await blockBlobClient.exists();

    if (!exists) {
      const externalApiUrl = NEXT_PUBLIC_PLAYWRIGHT + "/api/screenshot?url=" + url;
      const response = await axios.get(externalApiUrl);
      const imageData = response.data.screenshot;
      const decodedImageData = Buffer.from(imageData, "base64");

      await blockBlobClient.uploadData(decodedImageData);
      console.log("Image was uploaded");

      res.setHeader("Content-Type", "image/png");
      res.status(200).end(decodedImageData, "binary");
    } else {
      const downloadResponse = await blockBlobClient.downloadToBuffer();
      console.log("file is exist");

      res.setHeader("Content-Type", "image/png");
      res.status(200).end(downloadResponse, "binary");
    }
  } catch (error) {
    return res.status(500).json({ error: "Can't get content data" });
  }

When actually executed, the console now displays the message "file is exist" if a file exists and displays the image loaded from storage. When taking a screenshot, it now waits 2 seconds, which speeds up the display of the image.

Summary

It is now possible to get a screenshot by setting up the environment and how to use Playwright multiple times. For this screenshot image, prepare an API to call it, specify the URL, and the image will be displayed.

This makes it possible to use screenshots when displaying results in Sitecore Search.

Tags