業務でNestJSに触れる機会があったので、参考サイトを見ながらサンプルプロジェクトを作ってみました。
参考サイトから読み替えた部分や、バージョンアップによって修正しなければいけない部分があったので、備忘録としてまとめておきます。
対象環境
- Node.js: v16.14.2
- @nestjs/core: v8.4.6
- graphql: v15.8.0
- apollo-server-express: v3.8.1
npm から yarn へ
読み替えた部分としては npm
から yarn
への変更。
たいした変更ではないですが、一応変更後のコマンドを書いておきます。
yarn add -g @nestjs/cli
※ @nestjs/cli
はグローバルへのインストールが必要
yarn add @nestjs/graphql graphql@^15 apollo-server-express
ApolloDriver の追加
参考サイトのコードのままサーバを起動すると、以下のようなメッセージが表示されて起動が失敗します。
[Nest] 10403 - 06/01/2022, 2:49:31 PM ERROR [GraphQLModule] Missing "driver" option. In the latest version of "@nestjs/graphql" package (v10) a new required configuration property called "driver" has been introduced. Check out the official documentation for more details on how to migrate (https://docs.nestjs.com/graphql/migration-guide). Example:
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
})
エラーメッセージがわかりやすくて素晴らしい。
基本は書いてある通りなのですが、 @nestjs/graphql
がv10にバージョンアップする際に破壊的な(バージョンアップ後にコードを修正しないと起動失敗するような)変更があったらしい。
メッセージに記載のページ をもとに下記をインストールします。
yarn add @nestjs/apollo
修正したコードがこちら。
// src/app.module.ts
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'; // <-- 追加
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { join } from 'path';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TodoModule } from './todo/todo.module';
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({ // <-- 変更
driver: ApolloDriver, // <-- 追加
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
sortSchema: true,
}),
TodoModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
このように記載することで、サーバが起動できるようになります。
Mutationの追加
最後に参考サイトには無かったMutationを追加してみます。
IDにUUIDを使いたかったので、以下をインストールする。
yarn add uuid
まずserviceを修正です。
よくわかってないところなのですが、ModelはDDDでいうドメインモデルという認識でいいんでしょうか。
認識が正しい場合は Todo
モデル内に初期化処理を書くべきでしょうが、今回はserviceの関数内で実装してしまいます。
いわゆるドメインモデル貧血症状態?(覚えたての言葉を使ってみたくなる病)
// src/todo/todo.service.ts
import { v4 } from 'uuid'; // <-- 追加
import { Injectable, NotFoundException } from '@nestjs/common';
import { Todo, TodoStatus } from './models/todo.models';
@Injectable()
export class TodoService {
:
中略
:
// 新しいTodoを追加する。
// ID等、自動的に設定できる項目は引数として受け取らないようにする。
insert(title: string, description: string): Todo { // <-- 関数追加
const todo = new Todo();
todo.id = v4();
todo.title = title;
todo.description = description;
todo.status = TodoStatus.NEW;
todo.createdAt = new Date();
todo.updateAt = new Date();
this.todos.push(todo);
return todo;
}
}
続いてresolverの修正。
// src/todo/todo.resolver.ts
import { Args, ID, Mutation, Query, Resolver } from '@nestjs/graphql'; // <-- Mutation追加
import { Todo } from './models/todo.models';
import { TodoService } from './todo.service';
@Resolver()
export class TodoResolver {
constructor(private todoService: TodoService) {}
:
中略
:
// MutationデコレータでMutationを定義
// https://docs.nestjs.com/graphql/mutations
// Queryデコレータと同様に引数にArgsデコレータで定義ができる。
@Mutation(() => Todo) // <-- 関数追加
insert(
@Args('title') title: string,
@Args('description') description: string,
): Todo {
return this.todoService.insert(title, description);
}
}
以上で、 shema.gql
にMutationが追加されます。
type Mutation {
insert(description: String!, title: String!): Todo!
}
Playgrapundで適当なMutationを実行することで動作を確認できる。
mutation {
insert(
title: "テスト"
description: "テスト用のTODOです。"
){
id
}
}
{
"data": {
"insert": {
"id": "f532372f-e56f-4add-a718-071e0558aa75"
}
}
}
query {
findAll {
id
title
description
status
createdAt
updateAt
}
}
{
"data": {
"findAll": [
{
"id": "6e099204-1c2f-464f-a7cc-18eb5dd383f0",
"title": "テスト",
"description": "テスト用のTODOです。",
"status": "NEW",
"createdAt": "2022-06-01T15:26:00.368Z",
"updateAt": "2022-06-01T15:26:00.368Z"
}
]
}
}
query {
findOneById(
id: "6e099204-1c2f-464f-a7cc-18eb5dd383f0"
) {
id
title
description
status
createdAt
updateAt
}
}
{
"data": {
"findOneById": {
"id": "6e099204-1c2f-464f-a7cc-18eb5dd383f0",
"title": "テスト",
"description": "テスト用のTODOです。",
"status": "NEW",
"createdAt": "2022-06-01T15:26:00.368Z",
"updateAt": "2022-06-01T15:26:00.368Z"
}
}
}
おわりに
後発のフレームワークだけあって、だいぶ使いやすい印象でした。
eslint, prettier, jestが標準装備で、テストコードを生成してくれるところも好印象です。
しばらく使ってみて、感触を確かめてみたいと思います。