Closed6
NestJS Prisma training
Getting start
コード書いて起動しようとしたらエラー
[Nest] 22573 - 11/13/2021, 11:53:53 PM LOG [NestFactory] Starting Nest application...
[Nest] 22573 - 11/13/2021, 11:53:53 PM ERROR [ExceptionHandler] @prisma/client did not initialize yet. Please run "prisma generate" and try to import it again.
In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues
prisma generate
してもだめ。
PrismaClient の型が違いました
prisma.service.ts
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
- import { PrismaClient } from '@prisma/client/scripts/default-index';
+ import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
/**
* https://docs.nestjs.com/recipes/prisma#prisma
* onModuleInitはオプションです。
* 省略した場合、Prismaはデータベースへの最初の呼び出しで遅延接続します。
* Prismaには接続を破棄する独自のシャットダウンフックがあるので、
* onModuleDestroyは使いません。
*/
async onModuleInit(): Promise<any> {
await this.$connect();
}
async enableShutDownHooks(app: INestApplication) {
this.$on('beforeExit', async () => {
await app.close();
});
}
}
Intellij の型補完を信じすぎた。
リクエストを送る
はい
はい。大丈夫そう。
最初、こうする
既存のコードをコピペしてまったく新しいデータベースで試したい場合。まずはコードをコピーする。
インストール
yarn install
データベースを立ち上げる
docker compose up --remove-orphans
マイグレーションを適用する
コピーしたからなどの理由で migrations/
が存在する場合は削除すること。
yarn prisma migrate dev --name init
DBスキーマから型ファイルを生成
yarn prisma generate
モデル(ドメイン?)ごとに切ってみる
わからないところはとりあえずファイルをわけるようにした。
src/models/
└── posts
├── dto
│ └── find-post.dto.ts
├── entities
│ └── post.entity.ts
├── post.controller.spec.ts
├── post.controller.ts
├── post.module.ts
├── post.service.ts
├── repositories
│ └── post.repository.ts
└── serializers
└── published-post.serializer.ts
DTO でバリデーション
/post/:id
のエンドポイントに対してバリデーションしてみる。
ここをみながら。
yarn add class-validator class-transformer
とりあえずオプションはなしにして、Pipeを追加する。
amin.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { PrismaService } from './prisma.service';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
+ // バリデーションPipeを追加
+ app.useGlobalPipes(new ValidationPipe());
// Primsaがアプリケーションのシャットダウン前に `process.exit()` に反応してシャットダウンされてしまう仕様なので
// アプリケーションのシャットダウンフックに反応するよう設定を追加する
const prismaService: PrismaService = app.get(PrismaService);
await prismaService.enableShutDownHooks(app);
await app.listen(3001);
}
bootstrap();
DTO にバリデーションを追加。あれ、この @IsNumberString
ってのはどこにあるんだ。
こっちっぽい。今回は数値に変換したいので @IsNumberString
にする。
おお〜ちゃんとバリデーションされてるぅ〜。
エラーメッセージをカスタマイズ
したくなるよね。
find-post.dto.ts
import { IsNumberString } from 'class-validator';
export class FindPostDto {
@IsNumberString(
{},
{
message: 'IDは数値です',
},
)
id: string;
}
これでいいらしい。
よきよき。
ペイロードのトランスフォーム
DTO => ドメインオブジェクトは誰の責務にするか常に悩むけど、どうやらNestJSではサポートされているらしい…?
ごめん違うか。ペイロード(Pure)=> DTO ってことか。
Service のパラメータは何(どのレイヤ)にするのがよいか?
DTOがいいと思う。Entity レイヤにもうひとつ更新や作成用のドメインオブジェクトを用意するのはさすがに大変。
- コントローラーはリクエストをDTOに変換する(自動でtransformできるならそれで)
- コントローラーはサービスを呼び出す
- サービスはDTOを受け取り、エンティティを返すか、外界への副作用を実行するためのリポジトリまたは他のサービスを呼び出す
- コントローラーはエンティティを受け取り、シリアライズして返す
このスクラップは2021/12/01にクローズされました