🎃

Deno FreshアプリケーションのDB接続にPrisma Clientを使う

2022/10/20に公開約3,900字

https://scrapbox.io/uki00a/PrismaのDenoサポートについて
https://github.com/prisma/prisma/issues/2452

でPrismaとDenoの人たちによって着々と進められていたプロジェクトが成就しついにDeno DeployでPrismaが使えるようになったのでFreshから試してみた。

環境

  1. Deno Deployにデプロイする
  2. Prisma Data PlatformからDBサーバーに到達できる必要がある
  3. DBサーバーにはSupabase CloudのPostgreSQLを使う

Prisma Data Platform

https://www.prisma.io/data-platform

PrismaのData Proxyという機能を利用するためのオフィシャルな方法。

Prisma ClientにDATABASE_URL="prisma://aws-us-east-1.prisma-data.com/?api_key=XXX"のような接続先を設定するとHTTP越しにクエリが実行される。

Denoにはpostgresドライバ がありDeno Deployでも利用できるが現時点ではDeno経由でPrisma Clientのコードを実行するにはData Proxy経由で接続する必要がある

Freshアプリケーション作成

https://fresh.deno.dev/docs/getting-started/create-a-project

のとうり。FreshドキュメントにDB層をどう構築するのかは例がなく以下のようなIssueも立っている

https://github.com/denoland/fresh/issues/336

Prisma Client構成

以下にドキュメントがある

https://www.prisma.io/docs/guides/deployment/deployment-guides/deploying-to-deno-deploy

schema.prismaをこう変更した

generator client {
  provider        = "prisma-client-js"
  output          = "../generated/client"
  previewFeatures = ["deno"]
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Event {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
}

環境変数を .env に記述。Prisma Data Platformの接続先を追加する

DATABASE_URL="prisma://aws-us-east-1.prisma-data.com/?api_key=XXX"
PRISMA_GENERATE_DATAPROXY="true"

migrateを使う版 DATABASE_MIGRATE_URL でダイレクトに postgres:// のSupabaseのホストを指定することができる。

db push/pullprisma:// ではできないのでこうした

DATABASE_URL="postgresql://postgres:PASSWORD@db.XXX.supabase.co:5432/postgres?schema=public" deno run -A --unstable npm:prisma db push

prisma generate

Prisma Clientのコードを生成する。PRISMA_GENERATE_DATAPROXY="true"でも--data-proxyつけてもどちらでもよし

deno run -A --unstable npm:prisma generate --data-proxy

generated/ にdenoディレクトリができる

❯ tree generated/                                                                                                                                                           
generated/
└── client
    ├── deno
    │   ├── edge.js
    │   ├── edge.ts
    │   ├── index.d.ts
    │   └── polyfill.js
    ├── edge.d.ts
    ├── edge.js
    ├── index-browser.js
    ├── index.d.ts
    ├── index.js
    ├── libquery_engine-darwin-arm64.dylib.node
    ├── package.json
    ├── runtime
    │   ├── edge-esm.js
    │   ├── edge.js
    │   ├── index-browser.d.ts
    │   ├── index-browser.js
    │   ├── index.d.ts
    │   └── index.js
    └── schema.prisma

API routesからDB接続

routes/api/counter.ts を用意。アクセスする度にDBにINSERTしてカウントアップするようにした。

import { PrismaClient } from '../../generated/client/deno/edge.ts'
import { HandlerContext } from "$fresh/server.ts";

const prisma = new PrismaClient();

export const handler = async (_req: Request, _ctx: HandlerContext): Promise<Response> => {
  await prisma.event.create({data:{}})
  const count = await prisma.event.count()
  return new Response(JSON.stringify({count}), {headers: {"Content-Type": "application/json"}});
};
❯ http http://localhost:8000/api/counter
HTTP/1.1 200 OK
content-length: 11
content-type: application/json
date: Thu, 20 Oct 2022 15:36:04 GMT
vary: Accept-Encoding

{
    "count": 5
}

Deploy

DATABASE_URL="prisma://、、、 をDeno Deploy環境にも設定してデプロイする

Discussion

ログインするとコメントできます