TypeScript + Nestjs + Prisma でGraphQLサーバー構築
概要
TypeScript + Nestjs + Prisma でGraphQLサーバー構築。
ついでにdocker-composeでmysqlサーバーも構築。
Nestjsとは?
NestJSは、素早いサーバー実装を可能にし、テストしやすく作ることを目指したTypescript製のWebフレームワークです。GraphQLを扱う際は、ApolloServerと一緒に使われることが多い印象。
Prismaとは?
3要素から成る、Node.jsとTypeScriptのORM。
- Type-safe database client: 型安全なORM
- Hassle-free migrations: 強力なMigration
- Visual database browser: DBをブラウザで見れたり、操作ができる
Rubyで言うActiveRecordのような確固たる地位を築きつつあるORM。
手順(簡単なUserモデルを作ってみる)
今回実装したコードは、Gitにて公開しています。
Nestjs: プロジェクト作成
$ npm install -g @nestjs/cli
$ nest new test-api
実行して、localhost:3000
にブラウザでアクセスしてみる。
$ cd test-api
$ npm run start
$ npx prisma init
Hello World!が表示される。
Prism: セットアップ
$ npm install prisma --save-dev
$ npm install @prisma/client
$ npx prisma init
prividerをmysqlに変更。
generator client {
provider = "prisma-client-js"
}
datasource db {
- provider = "postgresql"
+ provider = "mysql"
url = env("DATABASE_URL")
}
.envを編集。
- DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
+ DATABASE_URL="mysql://root:password@localhost:4406/mydb?schema=public"
mysqlの開発環境を構築
docker-composeでmysql環境を作る。
下記のレポジトリをテンプレートとして作成しています。
下記のディレクトリ構成を作っていきます。
$ tree docker -a
docker
├── .gitignore
├── conf
│ └── mysql.cnf
├── data
│ └── .gitkeep
└── mysql.env
必要なディレクトリを作成。
$ mkdir docker
$ mkdir docker/conf
$ mkdir docker/data
$ touch docker/data/.gitkeep
mysql.cnfを作成。
[mysqld]
skip-host-cache
skip-name-resolve
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
binlog_do_db = mydb
.gitignoreを作成。
data
mysql.envを作成。
MYSQL_ROOT_PASSWORD=password
MYSQL_PORT=3306
MYSQL_USER=mydb_user
MYSQL_PASSWORD=mydb_pwd
MYSQL_DATABASE=mydb
MYSQL_LOWER_CASE_TABLE_NAMES=0
docker-compose.yamlを作成。
version: '3'
networks:
overlay:
services:
mydb:
image: mysql:5.7
env_file:
- ./docker/mysql.env
container_name: "mydb"
restart: "no"
ports:
- 4406:3306
volumes:
- ./docker/conf/mysql.cnf:/etc/mysql/conf.d/mysql.conf.cnf
- ./docker/data:/var/lib/mysql
networks:
- overlay
$ docker-compose up --detach
Prisma: model作成
schema.prisma
に下記を追加。
model User {
id Int @id @default(autoincrement())
username String
displayName String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
マイグレーションを実行する。
$ npx prisma migrate dev --name user
prisma studioでデータを入力する。
$ npx prisma studio
NestjsServiceでPrismaClientを使う
src/prisma.service.ts
を作成する。
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() {
await this.$connect();
}
async enableShutdownHooks(app: INestApplication) {
this.$on('beforeExit', async () => {
await app.close();
});
}
}
この設定はオプショナルだが、未設定だと最初のDBアクセスの際にコネクションを張りに行く。
設定しておくと、サーバー起動時にコネクションを張ってくれる。
The onModuleInit is optional — if you leave it out, Prisma will connect lazily on its first call to the database. We don't bother with onModuleDestroy, since Prisma has its own shutdown hooks where it will destroy the connection. For more info on enableShutdownHooks, please see Issues with enableShutdownHooks
Resolver実装
GraphQLを扱うのに必要なパッケージをインストール。(公式)
$ npm i @nestjs/graphql @nestjs/apollo graphql apollo-server-express
Nest-cliのプラグインを追加。
{
"collection": "@nestjs/schematics",
- "sourceRoot": "src"
+ "sourceRoot": "src",
+ "compilerOptions": {
+ "plugins": ["@nestjs/graphql"]
+ }
}
app.module.ts
に3点の設定を加える。
- driverとして
ApolloDriver
を設定 - autoSchemaFileを指定
- sortSchemaをtrueに
@Module({
imports: [
GraphQLModule.forRoot({
driver: ApolloDriver,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
sortSchema: true,
}),
],
controllers: [AppController],
providers: [AppService, PrismaService, UsersResolver],
})
export class AppModule {}
user.model.ts
を作成する。
import { Field, ID, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class User {
@Field(() => ID)
id: number;
username: string;
displayName: string;
createdAt: Date;
updatedAt: Date;
}
src/user/user.service.ts
を作成する。
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { User } from 'src/models/user.model';
import { PrismaService } from 'src/prisma.service';
@Resolver(() => User)
export class UsersResolver {
constructor(private prisma: PrismaService) {}
@Query(() => [User])
async users() {
return this.prisma.user.findMany();
}
@Mutation(() => User)
async createUser(
@Args('username') username: string,
@Args('displayName') displayName: string,
) {
return this.prisma.user.create({ data: { username, displayName } });
}
}
動かしてみる
$ npm run start
ブラウザで開く。
$ open http://localhost:3000/graphql
リクエストが帰ってくるのを確認。
さいごに
GraphQLサーバー構築をする際は、ぜひともNestjs&Prismaを積極検討してみたいと思いました。
実際に実装するにあたって、参考になりそうなレポジトリがあったのでリンクを張っておきます。
あと、twitterで開発について情報発信していますので、よかったらフォローしてくださいmm
参考
Discussion