バックエンドエンジニアがGraphQL触ってみた

## はじめに

フロントエンド開発で頻繁に取り上げられるGraphQLについて、基本的な理解を深めることを目的にこの記事を作成しました。GraphQLの基本概念から始めて、簡易的なメモリ内データベースを用いたCRUD操作の実装に至るまでを説明します。

## GraphQLとは？

簡単に言うと、GraphQLはデータ通信のための超便利なクエリ言語のようです。

REST APIとはちょっと異なり、GraphQLを使えば、「必要なデータだけをピンポイントで教えてもらえる」ようになります。

これのおかげで、データが多すぎたり（オーバーフェッチ）、逆に足りなかったりすること（アンダーフェッチ）が減るわけです。便利ですよね。

### **ざっくりとしたGraphQLのキーポイントは以下の通りです：**

- **クエリ (Queries)**: 「このデータが欲しい！」とサーバーに伝える時に使います。RESTでいうGETリクエストに似ていますが、もっと自由に、自分の欲しい形でデータを指定できます。
- **ミューテーション (Mutations)**: 「データを変更したい！」ときに活躍します。新しいデータの作成、既存のデータの更新、データの削除がこれ一つでできます。さらに、操作後にどんなデータを受け取りたいかも指定可能です。
- **スキーマ (Schema)**: GraphQLで遊ぶ際のルールブックです。サーバーが扱うデータの種類や、データのやり取りの方法を定義します。
- **リゾルバ (Resolvers)**: クエリやミューテーションを受け取ったら、「オッケー、データを持ってくるね！」と動いてくれる部分です。サーバー側で頑張ってくれるんです。

GraphQLの利点は、「不要なデータを引き連れてきてしまう...」や「複数のリソースを一度に取得したいのに...」といったストレスが減ることにあります。

APIとのやり取りがスムーズになることで、開発が加速し、フロントエンドとバックエンドの開発効率も格段に向上します。このため、現代のウェブ開発において、GraphQLは非常に重要な技術となっています。

## GraphQL実装してみる

### 1. 環境

GraphQLサーバーを構築するためには、Node.jsが必要になるので公式サイトからダウンロードしておきます。

https://nodejs.org/en

### 2. プロジェクトの初期化

プロジェクトディレクトリを作成し、Node.jsプロジェクトの初期化を行います。

```bash
mkdir graphql-sample
cd graphql-sample
npm init -y
```

### 3. 必要なパッケージのインストール

GraphQLサーバーを構築するために`graphql`　と`express`、`express-graphql`をインストールします。

```bash

npm install express express-graphql graphql
```

### 4. サーバーの設定

`server.js`　ファイルをプロジェクトのルートに作成し、ExpressサーバーとGraphQLのエンドポイントを設定します。ここでは、ユーザー情報のCRUD操作を可能にする簡単なスキーマとリゾルバを定義しています。

```jsx

// 必要なライブラリをインポートする
const express = require('express'); // Express.js、Node.jsのフレームワーク
const { graphqlHTTP } = require('express-graphql'); // express-graphql、ExpressとGraphQLを統合するためのミドルウェア
const { buildSchema } = require('graphql'); // GraphQL.jsからスキーマを構築するための関数

// サンプルデータ：ユーザー情報を配列で保持
let users = [
  { id: 1, name: 'hoge hoge', email: 'hoge@example.xxx' },
  { id: 2, name: 'fuga fuga', email: 'fuga@example.xxx' }
];

// GraphQLスキーマの定義
// - Query: データを取得するためのクエリの定義
// - Mutation: データを変更（作成、更新、削除）するための操作の定義
// - User: ユーザーオブジェクトの型定義
const schema = buildSchema(`
  type Query {
    user(id: Int!): User
    users: [User]
  }
  type Mutation {
    createUser(name: String!, email: String!): User
    updateUser(id: Int!, name: String, email: String): User
    deleteUser(id: Int!): User
  }
  type User {
    id: Int
    name: String
    email: String
  }
`);

// ルートリゾルバ：クエリやミューテーションに対応する具体的な処理を定義
const root = {
  user: ({id}) => users.find(user => user.id === id), // 特定のIDを持つユーザーを検索
  users: () => users, // すべてのユーザーを返す
  createUser: ({name, email}) => { // 新しいユーザーを作成して追加
    const newUser = { id: users.length + 1, name, email };
    users.push(newUser);
    return newUser;
  },
  updateUser: ({id, name, email}) => { // 特定のユーザー情報を更新
    const user = users.find(user => user.id === id);
    if (!user) throw new Error('User not found');
    user.name = name || user.name;
    user.email = email || user.email;
    return user;
  },
  deleteUser: ({id}) => { // 特定のユーザーを削除
    const index = users.findIndex(user => user.id === id);
    if (index === -1) throw new Error('User not found');
    const deletedUser = users[index];
    users = users.filter(user => user.id !== id);
    return deletedUser;
  },
};

// Expressサーバーの設定
const app = express();
// GraphQLのエンドポイントを設定。
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  // graphiqlは、ブラウザベースのIDEで、開発者がGraphQLクエリを簡単にテストできるようにするツールです。
  graphiql: true,
}));

// サーバーを4000ポートで起動
app.listen(4000, () => console.log('Server running on http://localhost:4000/graphql'));
```

### 5. サーバーの実行

サーバーを起動し、`http://localhost:4000/graphql`にアクセスして、GraphQLのクエリを試してみましょう。

```bash
node server.js
```

以下のような画面になったら成功です。

![スクリーンショット 2024-03-20 21.47.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330132/c54a9955-7ee3-b745-5c43-66b7729411a7.png)


### 6. クエリの実行

`http://localhost:4000/graphql`にアクセスし、GraphiQLインターフェースが表示されるので、以下のクエリを入力し、`Run`ボタンをクリックして実行します。

- ユーザーの一覧を取得

```graphql
{
  users {
    id
    name
    email
  }
}
```

![スクリーンショット 2024-03-20 22.03.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330132/daf9088c-21f9-fa85-1a26-2fc8e9656499.png)


- 新しいユーザーを作成

```graphql
mutation {
  createUser(name: "new user", email: "new@example.xxx") {
    id
    name
    email
  }
}
```

![スクリーンショット 2024-03-20 22.05.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330132/9dce4188-55e6-e20b-664f-55ba3244cc3e.png)


- ユーザー情報を更新

```graphql
mutation {
  updateUser(id: 3, name: "update user") {
    id
    name
    email
  }
}
```

![スクリーンショット 2024-03-20 22.06.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330132/7b877689-1c37-eb08-e3aa-95101f3c718e.png)


- ユーザーを削除

```graphql
mutation {
  deleteUser(id: 3) {
    id
  }
}
```

![スクリーンショット 2024-03-20 22.06.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330132/07dab9cd-f0f3-f499-84c1-d945c5ee12be.png)


## まとめ

今回の記事で基本的なGraphQLサーバーの設定と、シンプルなクエリを実行してみました。

次のステップとして、より複雑なスキーマの定義や、データベースとの統合などに挑戦してみようと思います。