はじめに
TypeScriptとPrismaとNextJSを使ってGraphQLサーバーの作成を行います。
1.NestJSプロジェクトの作成
npm install -g @nestjs/cli
nest new my-app
インストール後、サーバを起動してみます。
cd my-app
npm run start
http://localhost:3000
にアクセスすると Hello World! が表示されます。
2.Prismaのセットアップ
npm install prisma --save-dev //Prismaのパッケージをインストール
npm install @prisma/client
npx prisma init //prismaの初期化
prisma/schema.prisma と .envファイルが生成されるので接続したいデータベースに合わせて設定していきます。
今回は、supabaseを使用します。
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=SCHEMA"
3.テーブルの作成
今回はタイトルと本文と公開フラグのカラムを持った Post テーブルを作成します。
model Post {
id Int @default(autoincrement()) @id
title String
content String
published Boolean @default(false)
}
以下のコマンドを実行し、マイグレーションファイルの生成とマイグレーションの実行します。
npx prisma migrate dev --name post
4. Prisma Studio でデータ追加してみる
PrismaにはPrisma Studioというデータベースに対してCRUDの操作ができるGUIが付いています。
以下のコマンドでPrisma Studioを起動して、レコードを追加してみましょう。
npx prisma studio
http://localhost:5555 にアクセスして Post テーブルにレコードを追加してみてください。
5.NestJSでPrismaクライアントを使用する
NestJSでPrismaクライアントを使用するために、src 配下に prisma.service.ts というファイルを作成し、次のコードを追加します。
、module,テストのファイルではproviderに記述しなければエラーが出る。
import { Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() {
await this.$connect();
}
}
これでPrismaServiceからDB操作のためのメソッドを呼び出すことができるようになりました。
6.GraphQLのパッケージをインストール
NestJSの GraphQLのページを参考に必要なパッケージをインストールします。
npm install @nestjs/graphql @nestjs/apollo graphql apollo-server-express
7.NestJSのGraphQLプラグインの有効化
NestJSのGraphQLプラグインを有効化するとコードをシンプルにできるので、nest-cli.json
に compilerOptions
を追加して有効化しておきます。
NestJS で GraphQL サーバーを開発の開発には、コードファーストとスキーマファーストのアプローチがあります。どちらを採用しても、「Schema、データ、Resolver を用意すれば GraphQL サーバーは動かせる」という原理に変わりありません。この選択は、Schema をどうやって作成するか という違いです。
今回はコードファーストのアプローチを取ります。
コードファーストのアプローチでは、TypeScriptのクラスとデコレータを使用してクラス定義からGraphQLのSDLを生成します。
このプラグインはコードファーストのアプローチのみ適用されます。
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": ["@nestjs/graphql"]
}
}
8.テーブルの各データをモデルとして定義
今回は一覧を取得、レコード新規作成したいので以下のようなモデルを実装します。
このクラスはレスポンスのシリアライザかつschema.gql自動生成のための情報です。
現時点のPostのDBテーブルの構造に合わせてPost のObject Typeを作成してみましょう。
Post クラスを作り、@ObjectType()
のデコレータを付けます。
@nestjs/graphql
モジュールから必要なデコレーターと型をインポートしています。
npm runstart:dev
を実行した際に、app.module.ts
のautoSchemaFile
で設定した場所に、自動的にschema.gql
が作成されます。
import { Field, ID, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class Post {
@Field(() => ID)
id: number;
title: string;
content: string;
published: boolean;
}
GraphQLプラグインを有効化していない場合は各プロパティに @Field()
を付ける必要がありますが、有効化している場合は@Field()
を勝手につけてくれます。
number はデフォルトではGraphQLの Float に変換されるため、ここでは ID になるよう明示的に @Field(() => ID)
を指定しています。
参照
9.Resolverの作成
続いて、GraphQLでデータ操作を行うためのResolverを作成していきます。
今回は、Post の一覧を取得するQueryとレコードを新規作成するMutationを作成します。
Resolverを作るには、Resolverクラスを作成し、@Resolver()
のデコレータを付けます。
そして、QueryとMutationの関数には @Query()
と @Mutation()
、引数には @Args()
を付けます。
これらの情報からGraphQLのスキーマが生成されます。
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { Post } from './models/post.model';
import { PrismaService } from 'src/prisma.service';
@Resolver(() => Post)
export class PostResolver {
constructor(private prisma: PrismaService) {}
@Query(() => [Post])
async posts() {
return this.prisma.post.findMany();
}
@Mutation(() => Post)
async createPost(
@Args('title') title: string,
@Args('content') content: string,
) {
return this.prisma.post.create({ data: { title, content} });
}
}
constructor(private prisma: PrismaService) {}
でインスタンス化しています。
QueryやMutationの関数の中では、PrismaClientを使ってレコードの取得や作成を行っています。
10. AppModuleに必要なモジュールとクラスを追加
graphqlモジュールをNestJSアプリケーションに組み込み初期化します。
AppModule に GraphQLModule と先程作成した PrismaService、 PostResolver を追加します。
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { PrismaService } from './prisma.service';
import { PostResolver } from './posts/posts.resolver';
import { join } from 'path';
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
}),
],
controllers: [AppController],
providers: [AppService, PrismaService, PostResolver],
})
export class AppModule {}
GraphQLModuleのforRoot()
には GraphQL のオプションを設定できます。
autoSchemaFile: join(process.cwd(), 'src/schema.gql')
は autoSchemaFileプロパティ
によって、プロジェクトのsrcディレクトリに自動的にGraphQLスキーマファイルが生成されるようにしています。
モデルを定義したファイルに適当なデコレータを付与することで、自動的にgqlファイルを作成するようにできます。
この設定により、NestJSアプリケーションにGraphQLのサポートが追加されます。
Moduleの補足
@Moduleデコレータのプロパティ
・providers: @Injectableデコレータが付いたクラスを記述
・controllers @Controllerデコレータが付いたクラスを記述
・imports: モジュール内部で必要な外部モジュールを記述
・exports: 外部のモジュールにエクスポートしたいもの
動作確認
npm run start
Queryで記事の一覧を取得してみます。
クエリ
``` query { posts { id title content published } } ```記事の作成をしてみます。
クエリ
``` mutation { createPost(title: "piyo", content: "3記事目の本文です。") { id title content published } } ```参照