0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NestJsでGraphQLしてみる

Last updated at Posted at 2025-01-24

前置き

件名のとおりだが、Prismaとか、フロントエンドとかゴチャゴチャしたものは省いて、NestJS + ApolloGraphQL 環境を構築する

※ 2025/01/27 加筆修正

この記事のコードは https://github.com/rk7fd3s/nestjs-apollo

環境

執筆時の環境は下記の通り

node 23.6.1
nestjs/cli 11.0.2

準備

まず、Nest CLI をグローバルにインストール。

npm install -g @nestjs/cli

nestコマンドでプロジェクトを作成。

nest new nestjs-apollo

※ nestjs-apollo は任意で

作成後は作成されたディレクトリに移動


不要なファイルの削除

  • src/app.controller.spec.ts
  • src/app.controller.ts
  • src/app.service.ts

上記のファイルは今回不要なので削除する。

src/app.module.ts を修正

上記削除したファイルを参照しているsrc/app.module.tsを下記のように修正する。

import { Module } from '@nestjs/common';

@Module({
  imports: [],
})
export class AppModule {}

パッケージインストール

NestJSからapplo, graphqlを使うためのパッケージをインストールする。

npm i @nestjs/graphql @nestjs/apollo

今回 @apollo/servergraphql は要らない

自動的にスキーマファイルを作成するためのコード

src/app.module.ts を下記のように修正します

import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import * as path from 'path';

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: path.join(process.cwd(), 'src/schema.gql'),
      sortSchema: true,
    })
  ],
})
export class AppModule {}

こうすることにより、npm run start でサーバを立ち上げた際に、 src/schema.gql にスキーマ情報を吐き出すようになります。

この段階ではスキーマ情報を作成する元が無いのでエラーとなります


ここから本番

User

今回試しに、ユーザ情報を格納するモジュールを作成してGraphQLでデータのやり取りをする。

モジュールとリゾルバー、サービスを作成

nest g module user --no-spec
nest g resolver user --no-spec
nest g service user --no-spec

今回、スペックファイルは作成しない(作りたい人はどうぞ)

上記コマンドを打つと

src/user/user.module.ts、src/user/user.resolver.ts、src/user/user.serice.ts が作成され、src/app.module.ts が修正される。

nestコマンドを使用しないで、各ファイルを作成してもOK.
参考 905cc96

モデルを作成

src/user/user.model.ts

IDと名前、作成日時、更新日時を持つモデルとして作成。

import { Field, ObjectType } from '@nestjs/graphql';

@ObjectType()
export class UserModel {
  @Field(() => String)
  id: string;

  @Field(() => String)
  name: string;

  @Field(() => Date)
  createdAt: Date;

  @Field(() => Date, { nullable: true })
  updatedAt: Date | null;
}

src/user/user.service.ts

上記モデルの情報を取得、更新するためのサービスを書きます

import { Injectable } from '@nestjs/common';
import { UserModel } from './user.model';

const users: UserModel[] = [];
let index: number = 1;

@Injectable()
export class UserService {
  constructor() {
    const dummyUser01: UserModel = {
      id: this.getNewUserId(),
      name: 'name 0001',
      createdAt: new Date('2000-01-01T01:01:01+09:00'),
      updatedAt: null,
    };
    users.push(dummyUser01);
    const dummyUser02: UserModel = {
      id: this.getNewUserId(),
      name: 'name 0002',
      createdAt: new Date('2000-01-23T12:34:56+09:00'),
      updatedAt: null,
    };
    users.push(dummyUser02);
  }

  /**
   * 新しいユーザIDの取得
   *
   * @returns 新しいユーザのID
   */
  getNewUserId = () => {
    const i = String(index++);
    return i.padStart(4, '0');
  };

  /**
   * 全ユーザ取得
   * @returns 全ユーザリスト
   */
  getUsers = (): UserModel[] => {
    return users;
  };

  /**
   * ユーザ情報取得
   *
   * @param id ユーザID
   * @returns ユーザ情報
   */
  getUser = (id: string): UserModel => {
    const user = users.find((user) => user.id === id);
    if (!user) {
      throw new Error('not found.');
    }
    return user;
  };

  /**
   * 新規ユーザ情報追加
   *
   * @param name ユーザ名
   * @returns
   */
  createUser = (name: string): UserModel => {
    const newUser = {
      id: this.getNewUserId(),
      name,
      createdAt: new Date(),
      updatedAt: null,
    };
    users.push(newUser);
    return newUser;
  };

  /**
   * ユーザ情報を更新
   * 
   * @param id ユーザID
   * @param name ユーザ名
   * @returns ユーザ情報
   */
  updateUser = (id: string, name: string) => {
    const user = users.find((user) => user.id === id);
    if (!user) {
      throw new Error('not found.');
    }
    user.name = name;
    user.updatedAt = new Date();
    return user;
  }

  /**
   * ユーザ情報を削除
   * 
   * @param id ユーザID
   * @returns ユーザ情報
   */
  deleteUser = (id: string) => {
    const user = users.find((user) => user.id === id);
    if (!user) {
      throw new Error('not found.');
    }

    for (let i = 0; i <= users.length; i++) {
      const user = users.shift()!;
      if (user.id !== id) {
        users.push(user);
      }
    }

    return user;
  }
}

今回、DBなど永続的記録をしないので、const users: UserModel[] = []; の中のデータを操作しています。
詳細な実装はお任せします。

src/user/user.resolver.ts

上記サービスを使って、GraphQLのAPIとしてリゾルバー登録していきます。

import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { UserModel } from './user.model';
import { UserService } from './user.service';

@Resolver(() => UserModel)
export class UserResolver {
  constructor(private readonly userService: UserService) {}

  // 全ユーザ取得
  @Query(() => [UserModel])
  async users() {
    return this.userService.getUsers();
  }

  // id指定でユーザ取得
  @Query(() => UserModel)
  async user(@Args('id') id: string) {
    return this.userService.getUser(id);
  }

  // nameを与えてユーザを追加する
  @Mutation(() => UserModel)
  async createUser(@Args('name') name: string): Promise<UserModel> {
    return this.userService.createUser(name);
  }

  // idで指定したユーザのnameを変更する
  @Mutation(() => UserModel)
  async updateUser(
    @Args('id') id: string,
    @Args('name') name: string,
  ): Promise<UserModel> {
    return this.userService.updateUser(id, name);
  }

  // idで指定したユーザを削除する
  @Mutation(() => UserModel)
  async deleteUser(@Args('id') id: string): Promise<UserModel> {
    return this.userService.deleteUser(id);
  }
}

サーバ立ち上げ

npm run start:dev

src/schema.gql が作成されたことが確認できるはずです。

postmanなどでリクエストを投げて動作を確認してください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?