Skip to content

Part 2 - Action Code

Below is the code for the action that we will be creating in this exercise. This action will download a random cat image from the Cat API and save it to the workspace.

import { createTemplateAction } from "@backstage/plugin-scaffolder-node";
import fs from "fs";
import { Readable } from "stream";
import { ReadableStream } from "stream/web";
import { finished } from "stream/promises";
import path from "path";

// types
export interface CatResult {
  id: string;
  url: string;
  width: number;
  height: number;
}

/**
 * Creates an `acme:example` Scaffolder action.
 *
 * @remarks
 *
 * See {@link https://example.com} for more information.
 *
 * @public
 */
export function createAcmeExampleAction() {
  // For more information on how to define custom actions, see
  //   https://backstage.io/docs/features/software-templates/writing-custom-actions
  return createTemplateAction<{
    myParameter: string;
  }>({
    id: "catscanner:randomcat",
    description: "Downloads a random cat image into the workspace",
    schema: {
      input: {
        type: "object",
        required: [],
        properties: {},
      },
    },
    async handler(ctx) {
      ctx.logger.info(
        `Running example template with parameters: ${ctx.input.myParameter}`
      );

      const catResult = await fetch(
        "https://api.thecatapi.com/v1/images/search"
      );

      const catData: Record<string, CatResult> = await catResult.json();

      const stream = fs.createWriteStream(
        path.join(ctx.workspacePath, "catimage.jpeg")
      );
      const { body } = await fetch(catData[0].url);

      await finished(Readable.fromWeb(body as ReadableStream).pipe(stream));

      ctx.logger.info("Cat image downloaded");
    },
  });
}