📝
【備忘録】Nest × Prisma × Typegraphql
前提
RDBはPostgreSQL。
Nxでmonorepo環境を作成済。
npx create-nx-workspace --preset=nest
必要なパッケージをインストール
npm i @nestjs/apollo @nestjs/graphql @prisma/client express-graphql graphql graphql-fields graphql-scalars nestjs-prisma prisma-case-format type-graphql typegraphql-prisma
npm --save-dev @types/express @types/supertest prisma source-map-support supertest ts-loader tsconfig-paths @types/graphql-fields
Prisma設定
初期化
npx prisma init
Generatorの設定
prisma init
で生成されたshema.prisma
ファイルに追記。
./prisma/shema.prisma
generator client {
provider = "prisma-client-js"
}
/* 追加 */
generator typegraphql {
provider = "typegraphql-prisma"
output = "../src/generated/typegraphql-prisma"
formatGeneratedCode = "prettier"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
DATABASE_URLの書き換え
./.env
DATABASE_URL="postgresql://【ユーザ名】:【パスワード】@【IPアドレス】:5432/【DB名】?schema=public"
project.jsonにコマンドを追加
project.json
{
...
"targets": {
...
"pull": {
"executor": "nx:run-commands",
"options": {
"command": "npx prisma db pull",
"cwd": "apps/sample"
}
},
"gen": {
"executor": "nx:run-commands",
"options": {
"commands": [
"prisma-case-format --file prisma/schema.prisma",
"prisma format",
"prisma generate"
],
"cwd": "apps/sample"
},
}
}
}
pull
を実行するとprisma/schema.prisma
にテーブル情報が追加される。
その後、gen
を実行するとsrc/generated
にmodels
やresolvers
が生成される。
Appの設定
context作成
src/context.ts
import { PrismaClient } from '@prisma/client'
export interface Context {
prisma: PrismaClient
}
export const prisma = new PrismaClient()
AppModule
を書き換える
サンプルを参考に書き換える。
※本当はproviders
に@/generated/typegraphql-prisma
のresolvers
(自動生成されたすべてのresolver)を指定できるっぽいけど、エラーが出て指定できない...
src/app.module.ts
import { Module } from '@nestjs/common'
import { ApolloDriver } from '@nestjs/apollo'
import { TypeGraphQLModule } from 'typegraphql-nestjs'
import path from 'path'
import { Context } from '@/context'
import { resolvers } from '@/resolvers'
import { prisma } from './context'
@Module({
imports: [
TypeGraphQLModule.forRoot({
driver: ApolloDriver,
path: '/',
emitSchemaFile: path.resolve(__dirname, './prisma/schema.graphql'),
validate: false,
context: (): Context => ({ prisma }),
}),
],
providers: [UsersCrudResolver],
})
export class AppModule {}
main.ts
を書き換える
src/main.ts
import 'reflect-metadata'
import { NestFactory } from '@nestjs/core'
import { ExpressAdapter, NestExpressApplication } from '@nestjs/platform-express'
import { AppModule } from '@/app.module'
async function main() {
const app = await NestFactory.create<NestExpressApplication>(AppModule, new ExpressAdapter())
await app.listen(3000)
}
main().catch(console.error)
カスタムリゾルバ
フィールドの追加
src/resolvers/CustomeUserResolver.ts
import { Ctx, FieldResolver, Resolver, Root } from 'type-graphql'
import { Context } from '@/context'
import { Articles, Users } from '@/generated/typegraphql-prisma'
@Resolver(() => Users /* model */)
export class CustomUsersResolver {
@FieldResolver(() => [Articles /* 追加するフィールドのmodel */], { nullable: true })
async articles(@Root() user: Users, @Ctx() { prisma }: Context): Promise<Articles[]> {
const articles = await prisma.articles.findMany({
where: { userId: user.userId } // 検索条件
})
return articles
}
@FieldResolver(() => Users, { nullable: true })
async fullName(@Root() user: Users, @Ctx() { prisma }: Context): Promise<string> {
return `${user.lastName} ${user.firstName}`
}
}
作成したカスタムリゾルバをproviderに追加
src/app.module.ts
...
import { CustomUsersResolver } from '@/resolvers/CustomUsersResolver';
@Module({
...
providers: [UsersCrudResolver, CustomUsersResolver],
})
Discussion