NestJSでGraphQLを使用する
- 1634単語
- 8分
- 12 Jul, 2024
GraphQL は、API のクエリ言語とサーバーサイドランタイムの仕様であり、クライアントがデータを正確に要求することを可能にします。この記事では、GraphQL の基本概念を紹介し、NestJS で GraphQL を統合および使用する方法について、Schema の定義、複雑なクエリ、およびミューテーションの実装を含めて説明します。
GraphQL の基本概念
GraphQL は Facebook によって開発された API 用のクエリ言語であり、REST API の柔軟かつ効率的な代替手段を提供します。GraphQL は、クライアントが必要とする正確なデータを要求できるようにし、複数のリソースからデータを取得するために必要なリクエストの数を減らすことができます。
主な概念には以下が含まれます:
- Schema:API でクエリ可能なすべてのデータタイプとその関係を定義します。
- Query:データを読み取るリクエストです。
- Mutation:データを変更するリクエストです。
- Resolver:クエリとミューテーションのリクエストを処理する関数です。
NestJS の GraphQL モジュール
NestJS は、コードファースト(code-first)およびスキーマファースト(schema-first)の両方の方法を使用して GraphQL スキーマを定義できる強力な GraphQL モジュールを提供しています。
NestJS での GraphQL の使用
プロジェクトディレクトリ構造
GraphQL を使用する際には、コードを整理するために特定のファイルとディレクトリを作成する必要があります:
1src/2├── app.module.ts3├── main.ts4├── user/5│ ├── user.model.ts6│ ├── user.input.ts7│ ├── user.resolver.ts8│ ├── user.service.ts
インストールと設定
- 必要なパッケージをインストール:
1npm install @nestjs/graphql @nestjs/apollo graphql apollo-server-express @nestjs/typeorm typeorm mysql2
- GraphQL モジュールとデータベース接続を設定:
src/app.module.ts
で GraphQL モジュールと TypeORM モジュールを設定します:
1import { Module } from "@nestjs/common";2import { GraphQLModule } from "@nestjs/graphql";3import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";4import { TypeOrmModule } from "@nestjs/typeorm";5import { join } from "path";6import { UserModule } from "./user/user.module";7import { User } from "./user/user.model";8
9@Module({10 imports: [11 GraphQLModule.forRoot<ApolloDriverConfig>({12 driver: ApolloDriver,13 autoSchemaFile: join(process.cwd(), "src/schema.gql"), // スキーマファイルを自動生成14 }),15 TypeOrmModule.forRoot({16 type: "mysql",17 host: "localhost",18 port: 3306,19 username: "root",20 password: "password",21 database: "test",22 entities: [User],23 synchronize: true,24 }),25 UserModule,26 ],27})28export class AppModule {}
コードファーストとスキーマファースト
コードファースト(Code-First)
コードファーストは、デコレーターを使用してスキーマを定義し、コンパイル時に自動的に GraphQL スキーマファイルを生成する方法です。この方法では、開発者はコードを通じて直接スキーマを定義および管理できます。
例:
1import { ObjectType, Field, Int } from "@nestjs/graphql";2import { Entity, Column, PrimaryGeneratedColumn } from "typeorm";3
4@Entity()5@ObjectType()6export class User {7 @PrimaryGeneratedColumn()8 @Field(() => Int)9 id: number;10
11 @Column()12 @Field()13 name: string;14
15 @Column()16 @Field()17 email: string;18}
スキーマファースト(Schema-First)
スキーマファーストは、手動でスキーマファイルを作成し、それを解析してタイプとリゾルバーを生成する方法です。この方法では、開発者は直接 GraphQL スキーマファイルを編集および管理できます。
例:
まず、スキーマファイルを作成します:
1type User {2 id: Int!3 name: String!4 email: String!5}6
7type Query {8 getUsers: [User]9}10
11type Mutation {12 createUser(name: String!, email: String!): User13}
次に、NestJS がこのスキーマファイルを使用するように設定します:
1import { Module } from "@nestjs/common";2import { GraphQLModule } from "@nestjs/graphql";3import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";4import { join } from "path";5import { UserModule } from "./user/user.module";6
7@Module({8 imports: [9 GraphQLModule.forRoot<ApolloDriverConfig>({10 driver: ApolloDriver,11 typePaths: ["./**/*.graphql"],12 }),13 UserModule,14 ],15})16export class AppModule {}
スキーマの定義
コードファーストモードでは、デコレーターを使用して既にスキーマを定義しました。
Resolver の作成と使用
src/user/user.resolver.ts
で、クエリとミューテーションを処理する Resolver を作成します:
1import { Resolver, Query, Mutation, Args } from "@nestjs/graphql";2import { User } from "./user.model";3import { CreateUserInput } from "./user.input";4import { UserService } from "./user.service";5
6@Resolver(() => User)7export class UserResolver {8 constructor(private readonly userService: UserService) {}9
10 @Query(() => [User])11 async getUsers(): Promise<User[]> {12 return this.userService.getUsers();13 }14
15 @Mutation(() => User)16 async createUser(@Args("input") input: CreateUserInput): Promise<User> {17 return this.userService.createUser(input);18 }19}
複雑なクエリの実装
src/user/user.resolver.ts
で、複雑なクエリを実装します:
1import { Resolver, Query, Args, Int } from "@nestjs/graphql";2import { User } from "./user.model";3import { UserService } from "./user.service";4
5@Resolver(() => User)6export class UserResolver {7 constructor(private readonly userService: UserService) {}8
9 @Query(() => [User])10 async getUsers(11 @Args("page", { type: () => Int, nullable: true }) page: number = 1,12 @Args("limit", { type: () => Int, nullable: true }) limit: number = 10,13 ): Promise<User[]> {14 return this.userService.getUsersWithPagination(page, limit);15 }16
17 @Query(() => [User])18 async searchUsers(19 @Args("keyword", { type: () => String }) keyword: string,20 ): Promise<User[]> {21 return this.userService.searchUsers(keyword);22 }23}24
25// src/user/user.service.ts26import { Injectable } from "@nestjs/common";27import { InjectRepository } from "@nestjs/typeorm";28import { Repository } from "typeorm";29import { User } from "./user.model";30import { CreateUserInput } from "./user.input";31
32@Injectable()33export class UserService {34 constructor(35 @InjectRepository(User)36 private usersRepository: Repository<User>,37 ) {}38
39 async getUsers(): Promise<User[]> {40 return this.usersRepository.find();41 }42
43 async createUser(input: CreateUserInput): Promise<User> {44 const user = this.usersRepository.create(input);45 return this.usersRepository.save(user);46 }47
48 async getUsersWithPagination(page: number, limit: number): Promise<User[]> {49 const [result] = await this.usersRepository.findAndCount({50 skip: (page - 1) * limit,51 take: limit,52 });53 return result;54 }55
56 async searchUsers(keyword: string): Promise<User[]> {57 return this.usersRepository58 .createQueryBuilder("user")59 .where("user.name LIKE :keyword", { keyword: `%${keyword}%` })60 .orWhere("user.email LIKE :keyword", { keyword: `%${keyword}%` })61 .getMany();62 }63}
フロントエンドとの連携
フロントエンド環境の設定
フロントエンドプロジェクトでは、通常 Apollo Client を使用して GraphQL API とやり取りします。まず、Apollo Client 関連の依存関係をインストールします:
1npm install @apollo/client graphql
GraphQL リクエストの送信
フロントエンドプロジェクトで Apollo Client を設定します:
1import { ApolloClient, InMemoryCache } from "@apollo/client";2
3const client = new ApolloClient({4 uri: "http://localhost:3000/graphql",5 cache: new InMemoryCache(),6});7
8export default client;
クエリとミューテーションの処理
Apollo Client を使用してクエリとミューテーションを送信します:
1import React from "react";2import { useQuery, gql } from "@apollo/client";3
4const GET_USERS = gql`5 query GetUsers {6 getUsers {7 id8 name9 email10 }11 }12`;13
14function Users() {15 const { loading, error, data } = useQuery(GET_USERS);16
17 if (loading) return <p>Loading...</p>;18 if (error) return <p>Error :(</p>;19
20 return data.getUsers.map(({ id, name, email }) => (21 <div key={id}>22 <p>23 {name}: {email}24 </p>25 </div>26 ));27}28
29export default Users;
ミューテーションの処理:
1import React, { useState } from "react";2import { useMutation, gql } from "@apollo/client";3
4const CREATE_USER = gql`5 mutation CreateUser($name: String!, $email: String!) {6 createUser(input: { name: $name, email: $email }) {7 id8 name9 email10 }11 }12`;13
14function AddUser() {15 const [name, setName] = useState("");16 const [email, setEmail] = useState("");17 const [createUser, { data, loading, error }] = useMutation(CREATE_USER);18
19 const handleSubmit = (e) => {20 e.preventDefault();21 createUser({ variables: { name, email } });22 setName("");23 setEmail("");24 };25
26 return (27 <div>28 <form onSubmit={handleSubmit}>29 <input30 value={name}31 onChange={(e) => setName(e.target.value)}32 placeholder="Name"33 />34 <input35 value={email}36 onChange={(e) => setEmail(e.target.value)}37 placeholder="Email"38 />39 <button type="submit">Add User</button>40 </form>41 {loading && <p>Loading...</p>}42 {error && <p>Error :(</p>}43 {data && <p>User {data.createUser.name} created!</p>}44 </div>45 );46}47
48export default AddUser;
フロントエンドアプリケーションでこれらのコンポーネントを使用します:
1import React from "react";2import { ApolloProvider } from "@apollo/client";3import client from "./apollo-client";4import Users from "./components/Users";5import AddUser from "./components/AddUser";6
7function App() {8 return (9 <ApolloProvider client={client}>10 <div>11 <h2>My first Apollo app 🚀</h2>12 <AddUser />13 <Users />14 </div>15 </ApolloProvider>16 );17}18
19export default App;
まとめ
この記事では、GraphQL の基本概念と、NestJS プロジェクトで GraphQL を統合および使用する方法について説明しました。GraphQL モジュールの設定、スキーマの定義、クエリとミューテーションの作成および実装、複雑なクエリの処理方法を通じて、開発者が GraphQL の強力な機能を最大限に活用して効率的で柔軟な API を構築できるようにします。最後に、Apollo Client を使用してフロントエンドプロジェクトで GraphQL API とやり取りする方法を示しました。これらの例を通じて、NestJS で独自の GraphQL API を作成し、さまざまなビジネスニーズに対応するフロントエンドプロジェクトとシームレスに統合できます。