0
Help us understand the problem. What are the problem?
Organization

最新のNestJSでGraphQLサーバを実装する

業務で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が標準装備で、テストコードを生成してくれるところも好印象です。
しばらく使ってみて、感触を確かめてみたいと思います。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?