Next.jsのAPIで動的に生成したOGを返す

2023/10/28に公開

OGP


https://sarutabiko.com/user/@sarutabiko

上記のような画像をX(旧Twitter)やFacebook、LINEなどにおいて生成した画像を返すようにする。

OGの実処理

APIで返す形で実装.
DynamicRoutingでIDを取得し、Prismaでデータベースからデータを取り出して、
それを元にCanvasに書いていく形.

/api/user/[id]/og.tsxで画像を返す,

handle関数

特に変更なし

export default async function handle(req, res) {
  try {
    switch (req.method) {
      case "GET": {
        if (req.query.id) {
          return await getUserOg(req, res);
        }
      }
      default:
        break;
    }
  } catch (error) {
    return res.status(500).json({ ...error, message: error.message });
  }
}

ユーザ情報を書きつつ画像を返す

canvas.toBuffer()で出力したimage/pngとしてクライアントに返せば良い.
prismaから取得した情報でTextや画像を添えて返す.

import { PrismaClient } from "@prisma/client";
import { createCanvas, registerFont, loadImage } from "canvas";

const prisma = new PrismaClient();


export const getUserOg = async (req, res) => {
  try {
    let whereQuery = { id: req.query.id };

    let user = await prisma.user.findUnique({
      where: whereQuery,
    });

    const current = process.cwd();
    const canvas = createCanvas(1200, 630);
    const ctx = canvas.getContext("2d");

    //draw title
    {
      let username = user.name;
      context.fillText(username, 100, 100);
    }

    //Prof image
    {
      const profImage = await loadImage(
       user.image
      );
      
      ctx.drawImage(
        profImage,
        300,
        300,
        50,
        50
      );
    }

    res.writeHead(200, {
      "Content-Type": "image/png",
      "Cache-Control": `immutable, no-transform, s-max-age=2592000, max-age=2592000`
    });
    res.end(canvas.toBuffer("image/png"));
  } catch (error) {
    console.error("Request error", error);
    res.status(500).json({ error: "Error", success: false });
  }
};

Discussion