Nextjs x Rails のXクローンにprismaを入れて楽(?)をする。 (original) (raw)
はじめに
おはようございます! torihaziです
今日は実務と並行して行っているNextjs x Rails のXクローンで使用予定の
Prismaについてぶっつけ本番で入れて使用感や導入方法などを
つらつらと書いていこうと思います!
今作っているのはこんな感じです
Prisma | Simplify working and interacting with databases
HCのCTOからの情報と公式ドキュメントの情報を読んで、なんとなく良さを言語化すると
- アプリで使う型定義の情報をフロントからコマンド1つでbackのdbから読み込んで一括生成してくれる(zod使うと)
- backのdbを修正してもそれを即座にコマンド実行でfrontの型定義に反映させることが可能
確かにreact-hook-formとか使うときにinputのschemaを手書きで毎回書いていたのが
コマンド生成によるもので使えるとなれば確かに楽になるし、
何よりdb側の修正に伴い、frontの方もコマンドで直してくれるのは保守面でも良さそう。
まだ良さが分かりきれていないので実際に入れてみる。
QuickStart
ここからは公式ドキュメントを読みながら進めていきます
Quickstart with TypeScript & SQLite | Prisma Documentation
公式の例はSQLiteを使っていますが、私は"Postgreを使った既存Project"に導入を考えているので
これに沿って進めていきます。
Prequisites
前提として
- package.jsonがあるnode.jsのprojectで
- nodejs入ってて
- 少なくとも1このテーブルがあるpostgreが稼働してて
らしいですが、これはクリアしてるので大丈夫そうです。
Set up Prisma ORM
npm使っているのでこのままいけそうです
npm install prisma --save-dev
で"prisma": "^5.20.0"
が入りました。
次に
npx prisma
なんかコマンドイメージがターミナルに表示されました。
あ、これはこれからはこうしたらできるよってことですか。なるほど。
次に
npx prisma init
これを入力すると prismaディレクトリと.envファイルが作成されて、ターミナルには
✔ Your Prisma schema was created at prisma/schema.prisma You can now open it in your favorite editor.
warn You already have a .gitignore file. Don't forget to add .env
in it to not commit any private information.
Next steps:
- Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
- Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver, mongodb or cockroachdb.
- Run prisma db pull to turn your database schema into a Prisma schema.
- Run prisma generate to generate the Prisma Client. You can then start querying your database.
- Tip: Explore how you can extend the ORM with scalable connection pooling, global caching, and real-time database events. Read: https://pris.ly/cli/beyond-orm
More information in our documentation: https://pris.ly/d/getting-started
こんなことを言われました。
.envファイルを.gitignoreに入れること忘れないでねというのと、次のやり方ですか
親切ですね。
ええとさっきのコマンドを打つと
- prismaディレクトリが新規作成されて、schema.prismaっていうdbで管理してるschemaとそのdbへの接続情報?を含んだものができる
- dbへの接続情報を書き込む用の.envファイルができる
らしいです。
.envはdbへの宛先を書き込む用で
schema.prismaにはそのdbと繋ぐ処理みたいなのと繋いで読み込んだ結果のschemaが今後追記されるって感じでしょうか。
Connecting your database
Connect your existing database using TypeScript and PostgresSQL | Prisma Documentation
これからdbに繋いでいくそうです。
prisma/schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
.env
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
.envの方の書き方は
DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=SCHEMA"
みたいです。HerokuとかAWSに向いてるとしたら面倒そうですが今回は
Dockerコンテナでdb動かしてるのでlocalhostとかでいけるかと。
なので最後の例の感じでしょうか。
DATABASE_URL="postgresql://janedoe:janedoe@localhost:5432/janedoe?schema=hello-prisma"
railsのdatabase.ymlを見れば埋められそうですね。
最後のスキーマは省略したらpublicで埋められるそうです。
If you're unsure what to provide for the schema parameter for a PostgreSQL connection URL, you can probably omit it. In that case, the default schema name public will be used.
Introspect your database with Prisma ORM
Introspection with Prisma ORM, TypeScript, and PostgreSQL | Prisma Documentation
ということでついにdbのデータを読み込んで、スキーマファイルを作るそうです。
公式から拝借。
npx prisma db pull
テーブルとかは作っているので、これを叩きます。
Error: P1001
Can't reach database server at localhost:5432
Please make sure your database server is running at localhost:5432
.
怒られました。
そうですね。backend動かしてませんでした。
docker compose up -d
して再度チャレンジ。
できない。
あれか、docker-compose.ymlにポート書いてないからかな。
ports:
- "5432:5432"
て感じで追加。
リベンジ。
ダメぽん。
試しにpingでも飛ばしてみるか。
nc -vz localhost 5432
pingはport指定できなかったのでncでやったけど、ダメでした。
あーあれか。database名が間違ってるとかかな。
調べる方法ってなんだ。
psql -l -p ポート番号 -h ホスト名
これをrails のコンテナから打てばいいのかな。
ということでdocker compose exec api bash
で入って
psqlしようとしたけど入ってない。
入れるか。
Ubuntu 20.04にPostgreSQLをインストールする方法 [クイックスタート] | DigitalOcean
apt install postgresql postgresql-contrib
psql -l -p 5432 -h db -U postgres
で入って、passwordはymlにdatabase.ymlに書いてあるのを使う。
そしたら
$ psql -l
以下は実行結果(例)
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
------------+-----------+----------+---------+-------+------------------------- postgres | *** | UTF8 | C | C | template0 | *** | UTF8 | C | C | =c/*** + | | | | | =CTc/ template1 | *** | UTF8 | C | C | =c/*** + | | | | | =CTc/
こんな感じで出てくるから左のnameから今回の開発用のdbの名前をもらってくればいい。
で修正。
ダメだ。
そもそもdocker コンテナのdbのログに疎通しているような素振りが見られない。
そもそもコンテナ外から
psql -l -p 5432 -h localhost -U postgres
がいけないのがまずい?
connection が refusedされたと書いてあるし。
ということでdocker の containerで動いている dbに対してアクセスする方法を調べる。
やっぱり特別な方法しなくていい。
普通にコンテナ外から
psql -l -p 5432 -h localhost -U ユーザ名
したらでいい。
docker compose ymlで ポートをバインドしてもなぜか
docker compose ps
で表示されない。
なんで。docker compose restart
してもダメ。
。。。。。。。。。。。。。。。。。。。。。。。。
なんで。
あれか。一回downしてみるか。
で再度upする。
でもう一回 ps見てみると
あら、見えた。反映されてる。
でもう一回コンテナ外のホストから
psql -l -p 5432 -h localhost -U 接続ユーザ名
あら。いけたわ
そしたらもういけるでしょ。
はい、ビンゴ。
✔ Introspected 4 models and wrote them into prisma/schema.prisma in 75ms
Run prisma generate to generate Prisma Client.
いけました。
これはあれですね。
docker compose ps
でちゃんとポートバインドしてホストから覗けるかちゃんと確認する手順を入れて欲しいですね。
公式さん。
でさっきのpullしたら確かにできた
schema.prismaにこんな感じのものが追加されてる。これは公式のサンプルだけど。
model Post { id Int @id @default(autoincrement()) title String @db.VarChar(255) createdAt DateTime @default(now()) @db.Timestamp(6) content String? published Boolean @default(false) authorId Int author User @relation(fields: [authorId], references: [id], onDelete: NoAction, onUpdate: NoAction) }
model Profile { id Int @id @default(autoincrement()) bio String? userId Int @unique user User @relation(fields: [userId], references: [id], onDelete: NoAction, onUpdate: NoAction) }
model User { id Int @id @default(autoincrement()) name String? @db.VarChar(255) email String @unique @db.VarChar(255) posts Post[] profile Profile? }
で、このあとは?
prisma generate をやれとあるが。
一旦休憩。
Baseline your database
これはmigrationだからやらなくていい。
Install Prisma Client
npm install @prisma/client
らしいが。入れて。これはなんのため?
そういえばzodを使って型定義まで作ってくれるとあったが
どうするのだろうか。
調べるか。
とりあえず公式ドキュメントでお世話になりそうなのはここまでかな?
あとはgenerateすればなんとかなるっぽい。
npx prisma studioってすればwebのguiにつながって pgadminみたいになることも確認できた
zodと合わせる
zod-prisma-typesを活用して型安全なアプリケーションを構築する
多分この人のものを使えばいける。
npm install zod-prisma-types
らしいけどこれzod自体を入れなくてもいけるのかな?
とりあえず入れずにやってみる。
入れた後にschema.prismaに次を追加。
generator zod { provider = "zod-prisma-types" output = "./generated/zod" // 出力ディレクトリの指定 useMultipleFiles = true // スキーマを複数ファイルに分割 writeBarrelFiles = false // バレルファイルの生成を無効化 createInputTypes = false // 入力タイプの生成を無効化 createModelTypes = true // モデルタイプの生成を有効化 addInputTypeValidation = true // 入力タイプに対するバリデーションの追加 createOptionalDefaultValuesTypes = true // デフォルト値を持つフィールドをオプショナルに createRelationValuesTypes = true // リレーションフィールドを含むタイプの生成 createPartialTypes = true // 全フィールドをオプショナルにしたパーシャルタイプの生成 useDefaultValidators = false // Zodのデフォルトバリデータの使用を無効化 }
なんか説明あるけど、とりあえずこの人のを写した。
あとzodもやっぱり入れた。
npm install zod
OK。入れたので
npx prisma generate
多分これで色々作ってくれるはず。
おーでけた。
generated/zodの下に
inputTypeSchemasとmodelSchemaディレクトリができて
今backendで持っているdbのスキーマをそのままzodで書いたような感じで出てる
例えばmodelSchema/usersSchema.tsには
import { z } from "zod";
///////////////////////////////////////// // USERS SCHEMA /////////////////////////////////////////
export const usersSchema = z.object({ id: z.bigint(), email: z.string(), encrypted_password: z.string(), profile: z.string().nullable(), place: z.string().nullable(), web: z.string().nullable(), birth: z.string().nullable(), reset_password_token: z.string().nullable(), reset_password_sent_at: z.coerce.date().nullable(), remember_created_at: z.coerce.date().nullable(), confirmation_token: z.string().nullable(), confirmed_at: z.coerce.date().nullable(), confirmation_sent_at: z.coerce.date().nullable(), unconfirmed_email: z.string().nullable(), created_at: z.coerce.date(), updated_at: z.coerce.date(), jti: z.string(), });
export type users = z.infer;
///////////////////////////////////////// // USERS PARTIAL SCHEMA /////////////////////////////////////////
export const usersPartialSchema = usersSchema.partial();
export type usersPartial = z.infer;
///////////////////////////////////////// // USERS OPTIONAL DEFAULTS SCHEMA /////////////////////////////////////////
export const usersOptionalDefaultsSchema = usersSchema.merge( z.object({ id: z.bigint().optional(), email: z.string().optional(), encrypted_password: z.string().optional(), }) );
export type usersOptionalDefaults = z.infer;
export default usersSchema;
こんな感じで。
すげー。
ということはこれゆくゆくはmigrateとかして変わっていき次第にnpx prisma generate
すれば
dbのschema読み込んで、このファイルを更新していってくれるのか。
手書きでreact-hook-form用のzodスキーマをずらずら描かなくていいし、
何よりファイルの置き場所としても確立されるから分かりやすいし。
確かにすごいかも、しれない?
使っていくうちにその良さがわかると思う。
終わりに
とりあえず入れることはできたし、ようやくスタート地点に立てた。
ちなみにprisma studioの画面はこんな感じ。
frontからmigratieすることもできるそう。
使い込んでいって、選択肢の1つとしていきたい