Initialize NestJS Shared Library for “model” with Prisma Support
Reference:
- https://javascript.plainenglish.io/nx-nest-prisma-graphql-single-data-model-definition-e601eaa372c6
- https://docs.nestjs.com/recipes/prisma
yarn add --dev prisma
nx g @nrwl/nest:library model
cd libs/model
../../node_modules/.bin/prisma init
Edit workspace.json
and add the following targets into “model
” project:
"prisma-generate": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "../../node_modules/.bin/prisma generate",
"cwd": "libs/model"
}
},
"migrate-save": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "../../node_modules/.bin/prisma migrate dev --create-only --preview-feature --schema ./prisma/schema.prisma",
"cwd": "libs/model"
}
},
"migrate-up": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "../../node_modules/.bin/prisma migrate dev --preview-feature --schema ./prisma/schema.prisma",
"cwd": "libs/model"
}
},
"migrate-reset": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "../../node_modules/.bin/prisma migrate reset --preview-feature --schema ./prisma/schema.prisma",
"cwd": "libs/model"
}
},
"migrate-deploy": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "../../node_modules/.bin/prisma migrate deploy --preview-feature --schema ./prisma/schema.prisma",
"cwd": "libs/model"
}
},
"migrate-status": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "../../node_modules/.bin/prisma migrate status --preview-feature --schema ./prisma/schema.prisma",
"cwd": "libs/model"
}
},
"studio": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "../../node_modules/.bin/prisma studio --schema ./prisma/schema.prisma",
"cwd": "libs/model"
}
}
schema.prisma File
Before you edit, it’s a good idea to install Prisma extension for VS Code.
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model Nonprofit {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
email String @unique
name String?
}
Create src/libs/
After editing, you can run migration by:
nx run model:migrate-up
Prisma Service in NestJS
Generate the PrismaService:
nx generate @nrwl/nest:service --name=prisma --project=model --directory=lib
Code for libs/model/src/lib/prisma/prisma.service.ts
:
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
/**
* https://docs.nestjs.com/recipes/prisma
*/
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
async onModuleInit() {
await this.$connect();
}
async onModuleDestroy() {
await this.$disconnect();
}
}
Generate NestJS Resource with GraphQL Code First
yarn add @nestjs/graphql graphql-tools graphql apollo-server-express
In file app/app.module.ts
, add the following inside “imports
“:
GraphQLModule.forRoot({
installSubscriptionHandlers: false,
// See: https://stackoverflow.com/a/61048144/122441
autoSchemaFile: process.env.NODE_ENV === 'development' ? 'apps/fund/schema.gql' : true,
}),
Now you can generate a skeleton resource: (Important: Make sure the name is plural, as it needs that to differentiate between collection and single document queries)
nx generate @nestjs/schematics:resource --name=Nonprofits --sourceRoot=apps/fund/src --type=graphql-code-first
Edit src/app/nonprofits/nonprofits.service.ts
, first you must inject PrismaService
:
constructor(private prismaService: PrismaService) {
}
After that you can use the Prisma client, for example:
import { Nonprofit } from './entities/nonprofit.entity';
// ...
async findAll(): Promise<Nonprofit[]> {
const docs = await this.prismaService.nonprofit.findMany();
console.debug('NonprofitsService.findAll:', docs);
return docs;
}
Make sure that you have proper fields in GraphQL entities. For example in src/app/nonprofits/entities/nonprofit.entity.ts
:
import { ObjectType, Field, Int, ID, GraphQLISODateTime } from '@nestjs/graphql';
@ObjectType()
export class Nonprofit {
@Field(() => ID, { description: 'ID' })
id: number;
@Field(() => GraphQLISODateTime, { description: 'Created at' })
createdAt: Date;
@Field(() => String, { description: 'Email' })
email: string;
@Field(() => String, { description: 'Name' })
name: string;
}
Executing GraphQL Queries
To use it, open GraphQL Playground at http://localhost:3333/graphql
Then you can do a query such as:
{
nonprofits {
id, createdAt, email, name
}
}
To manipulate database contents, you can use your favorite MySQL Client (like MySQL Workbench, etc.). You can also use Prisma Studio by running yarn nx model:studio
or:
cd libs/model
../../node_modules/.bin/prisma studio
Auto-Generate GraphQL Resolver for CRUD Queries and Mutations
After using Prisma for some time (I have ever used TypeORM before, and also Mongoose and Typegoose), there are things that I like:
- prisma migrate
- prisma studio
- the generated client typings/code completion is really good (see below)
However, compared to TypeORM in NestJS:
- we still need to create entity/input/output classes with GraphQL decorators
- Autogenerate GraphQL CRUD: With TypeORM there’s @nestjsx/crud (that is unfortunately seems slow development). With Prisma and Apollo-Server there is Nexus, however there’s no “official” way to integrate with NestJS yet -> discussion here: https://github.com/graphql-nexus/nexus/issues/386