📌

Cloud Functions for Firebase + Hono で POST リクエストを受ける

2024/09/25に公開

Hono を Cloud Functions for Firebase で動かすにあたり、事前の下調べで @hono/node-server を使うと POST リクエスト時に500エラーが発生する こと、また、この事象がまだ解決していないことがわかっていたので、@hono/node-server を使わず以下の記事を参考にアダプタ(handler)を用意しました。

https://zenn.dev/kazuph/articles/ee51d6cf08d620

ただ、そのままだとプリフライトリクエストが通らず POST リクエストがコケるため、レスポンスにヘッダーを含めるようにしてこれを回避します。

handler.ts
import { Request as FunctionRequest, Response } from "firebase-functions";
import { Hono } from "hono";

// biome-ignore lint/suspicious/noExplicitAny: <explanation>
export const handler = (app: Hono<any>) => {
  return async (req: FunctionRequest, resp: Response) => {
    const url = new URL(`${req.protocol}://${req.hostname}${req.url}`);

    const headers = new Headers();

    // biome-ignore lint/complexity/noForEach: <explanation>
    Object.keys(req.headers).forEach((k) => {
      headers.set(k, req.headers[k] as string);
    });
    const body = req.body;

    const newRequest = ["GET", "HEAD"].includes(req.method) ?
      new Request(url, {
        headers,
        method: req.method,
      }) :
      new Request(url, {
        headers,
        method: req.method,
        body: Buffer.from(typeof body === "string" ? body : JSON.stringify(body || {})),
      });
    const res = await app.fetch(newRequest);

    const contentType = res.headers.get("content-type");

    // ここから
    resp.status(res.status);
    resp.set(Object.fromEntries(res.headers));
    // ここまで

    if (contentType?.includes("application/json")) {
      resp.json(await res.json());
    } else {
      resp.send(await res.text());
    }
  };
};

プリフライトリクエストではコケたものの、CORS 対応そのものは CORS Middleware のドキュメントそのまま対応する形で完了します。

Discussion