使用NestJS和Prisma构建GraphQL服务器
简述
使用Node.js的后端框架NestJS和TypeScript的ORMPrisma来创建GraphQL服务器。
顺便说一下,Prisma也可以用于构建REST API,它并不特化于GraphQL。
然而,Prisma模式定义的结构非常接近GraphQL的SDL(Schema Definition Language = Schema定义语言),而且Prisma Client可以覆盖GraphQL的复杂性,因此我认为它与GraphQL的兼容性非常高。
引入步骤
由于NestJS的文档中分别包含了Prisma和GraphQL的内容,所以我们基本上会按照这些内容进行进展。
链接:
Prisma:https://docs.nestjs.com/recipes/prisma
GraphQL:https://docs.nestjs.com/graphql/quick-start
安装NestJS CLI
$ npm i -g @nestjs/cli
创建一个NestJS项目
$ nest new my-app
安装Prisma CLI和Prisma Client。
$ cd my-app
$ npm install @prisma/client
$ npm install --save-dev prisma
4. Prisma的配置
$ npx prisma init
当执行此命令时,将在根目录下生成prisma/schema.prisma和.env文件。
与数据库建立连接
根据自己准备的数据库编辑prisma/schema.prisma和.env文件。我自己是使用Docker搭建了一个Mysql容器,所以配置如下所示。
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
DATABASE_URL="mysql://root:password@db/development"
※@后面的db是容器名。
※development是表名,可以随意更改为其他合适的名称,没有问题。
version: '3.8'
services:
server:
build: .
volumes:
- ./:/usr/app
ports:
- '3000:3000'
tty: true
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- '3306:3306'
command: --default-authentication-plugin=mysql_native_password
volumes:
- ./prisma/mysql:/var/lib/mysql
按照公式文件所述,如果想要快速执行,使用SQLite是最简便的方法。
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
DATABASE_URL="file:./dev.db"
6. 定义架构
在schema.prisma中定义模式。这里以创建一个名为User的示例为例。
(↑に追加)
model User {
id Int @id @default(autoincrement())
registeredAt DateTime?
updatedAt DateTime?
email String?
name String
}
7. 将架构应用于数据库。
将在第6步中定义的模式应用到数据库中有两种方法。
Create migrations from your Prisma schema, apply them to the database, generate artifacts (e.g. Prisma Client)
$ prisma migrate dev --preview-feature
Push the Prisma schema state to the database
$ prisma db push --preview-feature
如果执行迁移命令migrate,将在prisma目录下生成一个migrations目录,并在其中为每个迁移生成一个单独的目录。
migration.sql文件中包含了用于应用架构的SQL语句。
migrate还提供了其他命令,如reset和status,请详见以下链接:
https://www.prisma.io/docs/reference/api-reference/command-reference#prisma-migrate-preview
├── prisma
│ ├── migrations
│ │ └── 20201220094108_
│ │ └── migration.sql
如果执行db push,将直接将模式应用到数据库中,而不会生成任何文件。
考虑到rails中更 commonly preferred ridgepole而不是migration,个人觉得可以使用db push。
创建一个处理PrismaClient的PrismaService。
为了使用NestJS处理Prisma Client API,我们将在src文件夹中创建prisma.service.ts。
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient
implements OnModuleInit, OnModuleDestroy {
async onModuleInit() {
await this.$connect();
}
async onModuleDestroy() {
await this.$disconnect();
}
}
安装与GraphQL相关的包。
npm i @nestjs/graphql graphql-tools graphql apollo-server-express
如果使用Fastify,请安装apollo-server-fastify来替代apollo-server-express。另外,在src/main.ts的app处将Fastify进行替换。
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
创建对象类型和解析器。
GraphQL的实现有两种方法:Code first和Schema first。这次我们使用了从代码创建模式的Code first方法。
import { ObjectType, Field, Int, HideField } from '@nestjs/graphql';
@ObjectType()
export class User {
@Field((type) => Int)
id: number;
@Field({ name: 'registeredAt' })
createdAt?: Date;
updatedAt?: Date;
email: string;
@HideField()
password: string;
name?: string;
}
import { Resolver, Query } from '@nestjs/graphql';
import { User } from '../models/user.model';
import { PrismaService } from '../prisma.service';
@Resolver((of) => User)
export class UserResolver {
constructor(private prisma: PrismaService) {}
@Query((returns) => [User])
async users() {
return this.prisma.user.findMany();
}
}
在这个时候,当我们在nest-cli.json的compilerOptions中添加GraphQL插件并使其生效时,可以在一定程度上减少代码量,非常方便。
"compilerOptions": {
"plugins": [
{
"name": "@nestjs/graphql/plugin",
"options": {
"typeFileNameSuffix": [".input.ts", ".model.ts"]
}
}
]
}
另外,还有一个从在第6步创建的 schema.prisma 中自动生成 NestJS 代码的生成器,但是它并没有得到官方的支持,因此在选择上仍然相当困难。
-
- https://github.com/EndyKaufman/typegraphql-prisma-nestjs-example
-
- https://github.com/wSedlacek/prisma-generators/tree/master/libs/nestjs
- https://github.com/unlight/prisma-nestjs-graphql
11. 在AppModule中导入PrismaService、GraphQLModule和UserResolver。
在AppModule中,我们将导入使用8创建的PrismaService,使用9安装的GraphQLModule和使用10创建的UserResolver。
@Module({
imports: [
GraphQLModule.forRoot({
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
debug: true,
playground: true,
}),
],
controllers: [AppController],
providers: [AppService, PrismaService],
})
校验行动

此外,正如所定义的autoSchemaFile一样,将自动生成一个名为src/schema.gql的模式定义文件。
到最后
查看了Nexus 1.0的发布说明后,我设法考虑如何将Nexus集成进Nest+Prisma,但我个人感觉目前在Nest+Prisma中使用Nexus似乎没有太多意义。
如果此文章有任何错误或者有其他更好的实践方法,请指正。感谢您的阅读。