Nextjs x Rails のXクローンにprismaを入れて楽(?)をする。 (original) (raw)

はじめに

おはようございます! torihaziです

今日は実務と並行して行っているNextjs x Rails のXクローンで使用予定の

Prismaについてぶっつけ本番で入れて使用感や導入方法などを

つらつらと書いていこうと思います!

今作っているのはこんな感じです

Prisma | Simplify working and interacting with databases

HCのCTOからの情報と公式ドキュメントの情報を読んで、なんとなく良さを言語化すると

確かにreact-hook-formとか使うときにinputのschemaを手書きで毎回書いていたのが

コマンド生成によるもので使えるとなれば確かに楽になるし、

何よりdb側の修正に伴い、frontの方もコマンドで直してくれるのは保守面でも良さそう。

まだ良さが分かりきれていないので実際に入れてみる。

QuickStart

ここからは公式ドキュメントを読みながら進めていきます

Quickstart with TypeScript & SQLite | Prisma Documentation

公式の例はSQLiteを使っていますが、私は"Postgreを使った既存Project"に導入を考えているので

Add Prisma ORM to an existing project using TypeScript and PostgreSQL (15 min) | Prisma Documentation

これに沿って進めていきます。

Prequisites

前提として

らしいですが、これはクリアしてるので大丈夫そうです。

Set up Prisma ORM

npm使っているのでこのままいけそうです

作業ディレクトリのrootディレクトリに移動して

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:

  1. 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
  2. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver, mongodb or cockroachdb.
  3. Run prisma db pull to turn your database schema into a Prisma schema.
  4. Run prisma generate to generate the Prisma Client. You can then start querying your database.
  5. 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に入れること忘れないでねというのと、次のやり方ですか

親切ですね。

ええとさっきのコマンドを打つと

らしいです。

.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つとしていきたい