前置き
件名のとおりだが、Prismaとか、フロントエンドとかゴチャゴチャしたものは省いて、NestJS
+ Apollo
で GraphQL
環境を構築する
※ 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/server
や graphql
は要らない
自動的にスキーマファイルを作成するためのコード
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などでリクエストを投げて動作を確認してください。