【NestJS】初心者がNestJSを用いてGraphQLのAPIを構築をする

GraphQLロゴ NestJS

NestJSとは

TypeScriptを用いてAPIを構築したいときのフレームワークの一つ。
何もせずに利用し始めるとREST APIが使えるが、
GraphQLのライブラリをいれることによりGraphQLのエンドポイントを作ることが可能。

今回やること

NestJSを用いて、GraphQLが扱えるAPIを構築する。

参考

公式サイトを参考に進める。

Documentation | NestJS - A progressive Node.js framework
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, i...

サンプルAPI構築

①インストール

公式サイトにあるように、nestコマンドをインストールして
それを利用することでサンプルAPIを簡単に作成できる。

$ npm i -g @nestjs/cli
$ nest new project-name

プロジェクトが作成されたら、プロジェクトのルートで必要なパッケージのインストールを行う。
(今回はyarnの利用を選択した)

$ yarn install

②API起動

READMEに記載の通り、以下のコマンドで起動することができる。

$ yarn run start
yarn run v1.22.22
$ nest start
[Nest] 46878  - 2024/06/23 12:34:41     LOG [NestFactory] Starting Nest application...
[Nest] 46878  - 2024/06/23 12:34:41     LOG [InstanceLoader] AppModule dependencies initialized +11ms
[Nest] 46878  - 2024/06/23 12:34:41     LOG [RoutesResolver] AppController {/}: +6ms
[Nest] 46878  - 2024/06/23 12:34:41     LOG [RouterExplorer] Mapped {/, GET} route +1ms
[Nest] 46878  - 2024/06/23 12:34:41     LOG [NestApplication] Nest application successfully started +4ms

localhost:3000にアクセスすると、「Hello World!」が返却される。

ここまでで、一般的なAPIを立ち上げることができた。

③ディレクトリ構成

srcディレクトリの構成は以下のようになっている。

$ tree src
src
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
└── main.ts

1 directory, 5 files
ファイル名概要
app.controller.tsAPIにおける一般的なController。
受け付けるメソッドやパスなどを書く。
app.service.tsAPIにおける一般的なService。
ロジックなどを書く。
app.module.tsNestJSはmoduleという単位で機能を集約する。
これはアプリケーション全体を取りまとめるmodule。

GraphQLを利用する

ここから、GraphQLを利用できるようにしていく。
参考にする公式サイトは以下の通り。

Documentation | NestJS - A progressive Node.js framework
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, i...
  1. コードを書いて、そこからスキーマを生成していく方法
  2. スキーマをベースに実装していく方法

という2通りの方法があるが、今回は1の方法で実装を進める。

①必要なパッケージをインストールする

$ yarn add @nestjs/graphql @nestjs/apollo @apollo/server graphql

②moduleを作成する

moduleとは、機能をひとまとめにする単位のこと。
ここから、Authorというオブジェクトを作成し、それをGraphQLで提供する実装をしていくが
このAuthorに関する実装をひとまとめにしておく場所になる。

自動生成してくれるコマンドがあるので、こちらを利用して自動生成する。

$ nest g module author

authorというディレクトリが作成され、author.module.tsが生成されていることが確認できる。

src
├── author
│   └── author.module.ts

③modelを作成する

moduleを作成するとauthorディレクトリが作成されるので、
その中にAuthorオブジェクトのmodelを作成してく。
これが、レスポンスオブジェクトのベースの形になる。

src/author/author.model.ts

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

// オブジェクト全体に対してdescriptionを記載することもできる
@ObjectType({ description: 'Authorオブジェクト' })
export class Author {
  // GraphQLには数値型はIntとFloatがあるので、Int利用を明記する
  @Field((type) => Int, { description: 'ID' })
  id: number;

  // descriptionにより、フィールドに関する説明を記載できる
  @Field((type) => String, { description: '名前' })
  name: string;

  // nullableの場合もここで指定する
  @Field((type) => Int, { nullable: true, description: '年齢' })
  age?: number;
}

@ObjetcType()を付与したクラスを作成し、そこにフィールドを記載する。
各フィールドには@Field()デコレータを用いて、フィールドに関する付加情報を記述する。

④resolverを作成する

resolverにはクエリに関する振る舞いを定義する。
レスポンスはどんな形か、リクエストできるパラメータは何か、どんなクエリを受け付けているかなどを記載する。

src/author/author.resolver.ts

import { Args, Int, Query, Resolver } from '@nestjs/graphql';
import { Author } from './author.model';

// Authorに相当するスキーマを返却することを宣言している
@Resolver((of) => Author)
export class AuthorResolver {
  // わかりやすさのため、データをベタ書き
  private authors: Author[] = [
    {
      id: 1,
      name: 'hoge',
      age: 10,
    },
    {
      id: 2,
      name: 'fuga',
    },
    {
      id: 3,
      name: 'piyo',
      age: 20,
    },
  ];

  // Authorの配列を返却することを宣言している
  // descriptionにより説明文も記載可能
  @Query((returns) => [Author], { description: 'Authorを全て取得する' })
  async getAuthor() {
    return this.authors;
  }

  // Authorを単体で返却することを宣言している
  // nullableのオプションをtrueに設定しているため、Authorオブジェクトもしくはnullが返却されることがわかる
  @Query((returns) => Author, {
    nullable: true,
    description: 'ID指定でAuthorを取得する',
  })
  // `id`というInt型の引数をリクエスト時に指定することで、idを使った絞り込みが行えることを明示している
  async findAuthor(
    @Args('id', { type: () => Int, description: '絞り込み用のID' }) id: number,
  ) {
    return this.authors.find((item) => item.id === id);
  }
}

⑤moduleにresolverを記載する

作成したresolverは、moduleに記載して、moduleとしてまとめる対象としておく。

src/author/author.module.ts

import { Module } from '@nestjs/common';
import { AuthorResolver } from './author.resolver';

@Module({
  providers: [AuthorResolver], // ここに追加
})
export class AuthorModule {}

⑥ルート要素のmoduleに追加

全体を取りまとめているapp.module.ts

  • GraphQLを利用すること
  • 先ほど作成したAuthorに関するmodule

を明記する。

app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GraphQLModule } from '@nestjs/graphql';
import { join } from 'path';
import { AuthorModule } from './author/author.module';
import { ApolloDriver } from '@nestjs/apollo';

@Module({
  imports: [
    // GraphQLを利用する際はこれを追加
    GraphQLModule.forRoot({
      driver: ApolloDriver,
      autoSchemaFile: join(process.cwd(), 'src/schema.gql'), // コードファーストで実装しているので、スキーマは自動生成される
      sortSchema: true,
    }),
    AuthorModule, // 作成したmoduleをここに記載
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

最終的なディレクトリ構成は以下の通り。

$ tree src
src
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
├── author
│   ├── author.model.ts
│   ├── author.module.ts
│   ├── author.resolver.spec.ts
│   └── author.resolver.ts
└── main.ts

動作確認

①サーバー起動

以下のコマンドを実行することで、サーバーを起動できる。

起動した際に、src/schema.gqlというファイルが自動生成されていればOK。

$ yarn run start:dev

src/schema.gql

# ------------------------------------------------------
# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
# ------------------------------------------------------

"""Authorオブジェクト"""
type Author {
  """年齢"""
  age: Int

  """ID"""
  id: Int!

  """名前"""
  name: String!
}

type Query {
  """ID指定でAuthorを取得する"""
  findAuthor(
    """絞り込み用のID"""
    id: Int!
  ): Author

  """Authorを全て取得する"""
  getAuthor: [Author!]!
}

descriptionに記載した内容が反映されつつ、GraphQLのスキーマが自動生成されていることがわかる。

②playground確認

http://localhost:3000/graphqlにアクセスすると、GraphQLのplaygroundを確認することができる。
SCHEMAタブにはスキーマに関する情報が出力されており、GraphQLのクエリも実行することができている。

descriptionを記載しておくことで、スキーマの説明が分かりやすくなるので
できる限り記載するクセを身に着けておくと良い。

まとめ

  • NestJSはAPIを構築するためのフレームワーク
  • NestJSは作ったものをmoduleという単位でまとめておくのがルール
  • GraphQLのライブラリを組み込むことで、GraphQLに対応させることができる
  • GraphQLではObjectTypeでデータ型を定義し、Resolverでクエリを処理する

タイトルとURLをコピーしました