🫥

oRPC + Better AuthをBunの組み込みサーバーで動かす

に公開

結論

index.ts
import { RPCHandler } from "@orpc/server/fetch";
import { CORSPlugin } from "@orpc/server/plugins";
import { router } from "./routes";
import { auth } from "./libs/auth";

const handler = new RPCHandler(router, {
    plugins: [
        new CORSPlugin({
            origin: "http://localhost:3000",
            allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
            allowHeaders: ["Content-Type", "Authorization"],
            credentials: true,
        }),
    ],
});

const CORS_HEADERS = {
    "Access-Control-Allow-Origin": "http://localhost:3000",
    "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
    "Access-Control-Allow-Headers": "Content-Type, Authorization",
    "Access-Control-Allow-Credentials": "true",
}

Bun.serve({
    port: 8000,
    async fetch(request: Request) {
        const { matched, response } = await handler.handle(request, {
            prefix: "/rpc",
            context: {
                headers: request.headers,
            },
        });

        if (matched) {
            return response;
        }

        if (request.method === "OPTIONS") {
            return new Response("OK", { headers: CORS_HEADERS });
        }

        const url = new URL(request.url);

        if (url.pathname.startsWith("/api/auth")) {
            const response = await auth.handler(request);
            Object.entries(CORS_HEADERS).forEach(([key, value]) => {
                response.headers.set(key, value);
            });
            return response;
        }

        return new Response("Not found", { status: 404 });
    },
});

このようにしてあげる。

解説

サーバーの起動・リッスン

他のフレームワーク(HonoやElysiaなど)と一緒にoRPCやBetter Authを使わない場合、Bunでは Bun.serve で組み込みサーバーを使って動かすのがセオリー。

oRPCのGetting StartedにはNodeサーバーアダプタを使った方法しか乗ってないが、以下のドキュメントには Bun.serve を使った方法が載っている

https://orpc.unnoq.com/docs/adapters/http

CORS

単にoRPCを使うだけなら、oRPCのCORSPluginを使えば、CORS関係のヘッダーが設定できるが、Better Authを使用する場合はBetter Authのルート用に個別にPreflight Requestをハンドリングしてあげるのと、Better AuthのハンドラからのレスポンスにCORSヘッダーを設定してあげる必要がある。

余談

今回のプロジェクトでは、ここからWebhookや外部連携用のAPIなども足していくことになったので、重厚になっちゃったとしても元からElysiaやHonoを使っておけばよかったなと思った。
(まぁでも今ならAIに任せればちゃちゃっとフレームワーク配下に置いてくれるけど)

以上

Discussion