T-CREATOR

Node.js で GraphQL サーバー構築:Yoga/Apollo を最小構成で立ち上げる

Node.js で GraphQL サーバー構築:Yoga/Apollo を最小構成で立ち上げる

GraphQL を使った API 開発を始めたいけれど、どのライブラリを選べばいいのか迷っていませんか。Node.js で GraphQL サーバーを構築する際、代表的な選択肢として GraphQL Yoga と Apollo Server があります。

本記事では、それぞれの特徴を理解しながら、最小構成でサーバーを立ち上げる方法を段階的に解説していきます。初めて GraphQL サーバーを構築する方でも、この記事を読めばすぐに動作するサーバーを作れるようになるでしょう。

背景

GraphQL とは何か

GraphQL は Facebook が開発したクエリ言語で、クライアントが必要なデータを必要な形で取得できる柔軟性が最大の特徴です。REST API と比較して、以下のような利点があります。

従来の REST API では、複数のエンドポイントにアクセスしてデータを取得する必要がありました。一方、GraphQL では単一のエンドポイントで、クライアントが欲しいデータだけを指定して取得できます。

過剰なデータ取得(Over-fetching)や不足したデータ取得(Under-fetching)の問題を解決し、ネットワーク効率を大幅に向上させることができるのです。

図の意図:REST API と GraphQL のデータ取得方法の違いを示します。

mermaidflowchart LR
  client1["クライアント"] -->|"/users/:id"| rest1["REST API"]
  client1 -->|"/posts/:userId"| rest2["REST API"]
  client1 -->|"/comments/:postId"| rest3["REST API"]

  client2["クライアント"] -->|"{ user { name posts { title } } }"| gql["GraphQL API"]
  gql -->|必要なデータのみ| client2

REST では複数のエンドポイントにアクセスする必要がありますが、GraphQL では 1 回のリクエストで必要なデータをすべて取得できます。

GraphQL Yoga とは

GraphQL Yoga は、The Guild が開発している軽量で使いやすい GraphQL サーバーライブラリです。特徴として、以下の点が挙げられます。

最小限の設定で動作するため、学習コストが低く抑えられています。また、最新の GraphQL 仕様に準拠しており、継続的にアップデートされているのも魅力ですね。

GraphQL Yoga は内部で Envelop プラグインシステムを採用しており、必要な機能を柔軟に追加できる拡張性を持っています。さらに、型安全性を重視した設計になっており、TypeScript との相性も抜群です。

Apollo Server とは

Apollo Server は、Apollo GraphQL が提供する成熟した GraphQL サーバーライブラリです。GraphQL サーバーの事実上の標準として、多くのプロダクション環境で採用されています。

豊富なエコシステムと充実したドキュメントが最大の強みでしょう。キャッシュ機能、エラーハンドリング、パフォーマンスモニタリングなど、プロダクション環境で必要な機能が揃っています。

Apollo Studio との統合により、クエリの実行状況やパフォーマンスを可視化できるのも大きなメリットです。エンタープライズレベルのアプリケーション開発には特に適していますね。

課題

GraphQL サーバー構築時の選択の難しさ

Node.js で GraphQL サーバーを構築しようとすると、まず多くのライブラリの選択肢に直面します。GraphQL Yoga、Apollo Server、Express + GraphQL など、それぞれに特徴があり、どれを選ぶべきか迷ってしまうでしょう。

公式ドキュメントを読んでも、実際にどの程度のコード量が必要で、どのような設定が必要なのかイメージしづらいものです。特に初学者にとっては、最小構成から始めて段階的に理解を深めたいという要望が強いですよね。

各ライブラリの学習曲線の違い

GraphQL Yoga と Apollo Server では、学習曲線や必要な知識に違いがあります。GraphQL Yoga はシンプルさを重視しているため、基本的な GraphQL の知識があればすぐに始められます。

一方、Apollo Server は機能が豊富な分、初期学習に時間がかかることがあるでしょう。キャッシュ設定、データソースの統合、エラーハンドリングなど、学ぶべき概念が多いのです。

また、TypeScript を使用する場合の型定義の方法も、ライブラリによって異なります。どちらを選ぶべきかは、プロジェクトの規模や要件によって変わってくるのです。

図の意図:GraphQL サーバー構築時の主要な検討ポイントを示します。

mermaidflowchart TD
  start["GraphQLサーバー構築"] --> question1{"プロジェクト規模"}
  question1 -->|小規模・プロトタイプ| yoga["GraphQL Yoga検討"]
  question1 -->|中〜大規模| apollo["Apollo Server検討"]

  yoga --> check1{"必要な機能"}
  apollo --> check2{"必要な機能"}

  check1 -->|シンプルなAPI| yoga_ok["Yoga採用"]
  check1 -->|高度な機能必要| reconsider["Apollo再検討"]

  check2 -->|キャッシュ・監視必要| apollo_ok["Apollo採用"]
  check2 -->|シンプルでOK| reconsider2["Yoga再検討"]

プロジェクトの規模と必要な機能に応じて、最適なライブラリを選択することが重要です。

セットアップの複雑さ

GraphQL サーバーのセットアップには、スキーマ定義、リゾルバー実装、サーバー起動など複数のステップがあります。特に初めての場合、どの順序で何を設定すればいいのか分かりづらいですよね。

また、開発環境と本番環境での設定の違いや、ミドルウェアの追加方法など、実践的な知識も必要になってきます。最小構成から始めて、必要に応じて機能を追加していくアプローチが理想的でしょう。

解決策

GraphQL Yoga の特徴と利点

GraphQL Yoga は「設定より規約」の思想で設計されており、最小限のコードで動作するサーバーを構築できます。デフォルトで GraphiQL(GraphQL のプレイグラウンド)が含まれており、すぐに API をテストできるのも便利です。

軽量で起動が速く、開発時のフィードバックループを短縮できます。また、Envelop プラグインシステムにより、必要な機能だけを選んで追加できる柔軟性があるのです。

CORS、ファイルアップロード、サブスクリプションなど、よく使う機能が標準で組み込まれているため、追加の設定なしで利用できるのも魅力ですね。

Apollo Server の特徴と利点

Apollo Server は、エンタープライズグレードの機能を提供する成熟したライブラリです。データソースの統合、キャッシュ戦略、エラーハンドリングなど、プロダクション環境で必要な機能が充実しています。

Apollo Studio との連携により、クエリのパフォーマンス分析やスキーマの管理が容易になります。大規模なチームでの開発には、この可視化機能が非常に役立つでしょう。

また、豊富なコミュニティとエコシステムがあり、問題解決のための情報が見つけやすいのも大きな利点です。プラグインやミドルウェアも充実していますね。

選択基準の明確化

プロジェクトの要件に応じて、以下の基準で選択するとよいでしょう。

GraphQL Yoga は、シンプルで軽量なサーバーが必要な場合や、プロトタイプを素早く作りたい場合に適しています。学習目的や小規模なプロジェクトでは、Yoga の手軽さが際立ちます。

一方、Apollo Server は、エンタープライズレベルのアプリケーションや、高度なキャッシュ・監視機能が必要な場合に適しています。既に Apollo Client を使用している場合は、サーバー側も Apollo で統一するとエコシステムの恩恵を最大限に受けられるでしょう。

#項目GraphQL YogaApollo Server
1学習コスト★★☆ 低い★★★ 中程度
2セットアップ時間★★★ 非常に速い★★☆ 速い
3機能の豊富さ★★☆ 基本的★★★ 豊富
4パフォーマンス監視★☆☆ 基本的★★★ 充実
5コミュニティサイズ★★☆ 成長中★★★ 大規模
6TypeScript サポート★★★ 優れている★★★ 優れている

両ライブラリとも TypeScript サポートは優れていますが、用途に応じて最適な選択が変わります。

具体例

GraphQL Yoga での最小構成サーバー構築

それでは、実際に GraphQL Yoga を使って最小構成のサーバーを立ち上げていきましょう。段階的に進めていきますので、一緒に実装していきますね。

プロジェクトの初期化

まず、新しいプロジェクトディレクトリを作成し、必要なパッケージをインストールします。

bash# プロジェクトディレクトリを作成
mkdir graphql-yoga-server
cd graphql-yoga-server

# package.json を初期化
yarn init -y

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

GraphQL Yoga と TypeScript 関連のパッケージをインストールしていきます。

bash# GraphQL Yoga と GraphQL をインストール
yarn add graphql-yoga graphql

# TypeScript 関連のパッケージをインストール
yarn add -D typescript @types/node ts-node

# tsconfig.json を生成
npx tsc --init

TypeScript の設定ファイル(tsconfig.json)は、必要に応じてカスタマイズできます。

TypeScript 設定の調整

生成された tsconfig.json を、Node.js プロジェクトに適した設定に調整します。

json{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

この設定により、型チェックが厳格に行われ、より安全なコードを書けるようになります。

スキーマの定義

GraphQL のスキーマを定義します。スキーマは API の設計図のようなもので、どのようなデータを取得・操作できるかを定義するものです。

src​/​schema.ts ファイルを作成しましょう。

typescript// src/schema.ts

// GraphQL スキーマを文字列で定義
export const typeDefs = `
  type Query {
    hello: String!
    user(id: ID!): User
    users: [User!]!
  }

  type User {
    id: ID!
    name: String!
    email: String!
  }
`;

このスキーマでは、hello クエリと、ユーザー情報を取得する userusers クエリを定義しています。

リゾルバーの実装

次に、スキーマで定義したクエリに対する実際の処理(リゾルバー)を実装します。リゾルバーは、クエリが実行されたときに呼ばれる関数です。

src​/​resolvers.ts ファイルを作成しましょう。

typescript// src/resolvers.ts

// サンプルデータ(実際のアプリケーションではデータベースから取得)
const users = [
  {
    id: '1',
    name: '山田太郎',
    email: 'yamada@example.com',
  },
  { id: '2', name: '佐藤花子', email: 'sato@example.com' },
  {
    id: '3',
    name: '鈴木一郎',
    email: 'suzuki@example.com',
  },
];

まず、サンプルデータを定義しました。実際のアプリケーションでは、データベースから取得することになります。

typescript// src/resolvers.ts(続き)

// リゾルバーの実装
export const resolvers = {
  Query: {
    // hello クエリのリゾルバー
    hello: () => 'GraphQL Yoga へようこそ!',

    // 特定の ID のユーザーを取得
    user: (_parent: unknown, args: { id: string }) => {
      return users.find((user) => user.id === args.id);
    },

    // すべてのユーザーを取得
    users: () => users,
  },
};

各クエリに対応するリゾルバー関数を定義しました。hello は固定の文字列を返し、user は引数で指定された ID のユーザーを、users はすべてのユーザーを返します。

サーバーの起動処理

最後に、GraphQL Yoga サーバーを起動する処理を実装します。src​/​index.ts ファイルを作成しましょう。

typescript// src/index.ts

import { createYoga } from 'graphql-yoga';
import { createServer } from 'node:http';
import { typeDefs } from './schema';
import { resolvers } from './resolvers';

// GraphQL Yoga サーバーを作成
const yoga = createYoga({
  schema: {
    typeDefs,
    resolvers,
  },
});

まず、必要なモジュールをインポートし、Yoga サーバーのインスタンスを作成します。

typescript// src/index.ts(続き)

// HTTP サーバーを作成して Yoga を統合
const server = createServer(yoga);

// サーバーを起動
const PORT = 4000;
server.listen(PORT, () => {
  console.log(`🚀 GraphQL Yoga サーバーが起動しました`);
  console.log(
    `http://localhost:${PORT}/graphql にアクセスしてください`
  );
});

HTTP サーバーを作成し、指定したポートで起動します。起動後、ブラウザで GraphiQL にアクセスできるようになります。

package.json にスクリプトを追加

開発を効率化するため、package.json に起動スクリプトを追加しましょう。

json{
  "scripts": {
    "dev": "ts-node src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

yarn dev コマンドで開発サーバーを起動でき、yarn build でビルド、yarn start で本番環境用のサーバーを起動できます。

サーバーの起動と動作確認

それでは、実際にサーバーを起動してみましょう。

bash# 開発サーバーを起動
yarn dev

ブラウザで http:​/​​/​localhost:4000​/​graphql にアクセスすると、GraphiQL が表示されます。以下のクエリを試してみてください。

graphqlquery {
  hello
  users {
    id
    name
    email
  }
}

このクエリを実行すると、すべてのユーザー情報が JSON 形式で返ってきます。たった数ステップで動作する GraphQL サーバーが完成しましたね。

図の意図:GraphQL Yoga サーバーのリクエスト処理フローを示します。

mermaidsequenceDiagram
  participant Client as クライアント
  participant Yoga as GraphQL Yoga
  participant Resolver as リゾルバー
  participant Data as データ

  Client->>Yoga: GraphQLクエリ送信
  Yoga->>Yoga: クエリ解析
  Yoga->>Resolver: 対応するリゾルバー呼び出し
  Resolver->>Data: データ取得
  Data-->>Resolver: データ返却
  Resolver-->>Yoga: 結果返却
  Yoga-->>Client: JSON レスポンス

クライアントからのクエリは、Yoga によって解析され、適切なリゾルバーが呼び出されて結果が返されます。

Apollo Server での最小構成サーバー構築

次に、Apollo Server を使った実装も見ていきましょう。基本的な流れは Yoga と似ていますが、細かな違いがあります。

プロジェクトの初期化と依存パッケージのインストール

新しいディレクトリで Apollo Server のプロジェクトを作成します。

bash# プロジェクトディレクトリを作成
mkdir apollo-server-demo
cd apollo-server-demo

# package.json を初期化
yarn init -y

Apollo Server に必要なパッケージをインストールしていきます。

bash# Apollo Server と GraphQL をインストール
yarn add @apollo/server graphql

# TypeScript 関連のパッケージをインストール
yarn add -D typescript @types/node ts-node

# tsconfig.json を生成
npx tsc --init

Apollo Server は @apollo​/​server パッケージから提供されています。

TypeScript 設定

Yoga のときと同様に、tsconfig.json を設定します。設定内容は基本的に同じです。

json{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

スキーマ定義

Apollo Server でのスキーマ定義は、Yoga とほぼ同じです。src​/​schema.ts ファイルを作成しましょう。

typescript// src/schema.ts

export const typeDefs = `#graphql
  type Query {
    hello: String!
    user(id: ID!): User
    users: [User!]!
  }

  type User {
    id: ID!
    name: String!
    email: String!
  }
`;

Apollo Server では、スキーマ定義の先頭に #graphql コメントを付けることで、エディタでのシンタックスハイライトが有効になります。

リゾルバーの実装

リゾルバーの実装も Yoga とほぼ同じです。src​/​resolvers.ts ファイルを作成します。

typescript// src/resolvers.ts

// サンプルデータ
const users = [
  {
    id: '1',
    name: '山田太郎',
    email: 'yamada@example.com',
  },
  { id: '2', name: '佐藤花子', email: 'sato@example.com' },
  {
    id: '3',
    name: '鈴木一郎',
    email: 'suzuki@example.com',
  },
];

// リゾルバーオブジェクト
export const resolvers = {
  Query: {
    hello: () => 'Apollo Server へようこそ!',
    user: (_: unknown, { id }: { id: string }) => {
      return users.find((user) => user.id === id);
    },
    users: () => users,
  },
};

データ構造とロジックは Yoga のときと同じですが、Apollo Server 特有の型定義を活用することもできます。

サーバーの起動処理

Apollo Server の起動処理は、Yoga と少し異なります。src​/​index.ts ファイルを作成しましょう。

typescript// src/index.ts

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { typeDefs } from './schema';
import { resolvers } from './resolvers';

// Apollo Server インスタンスを作成
const server = new ApolloServer({
  typeDefs,
  resolvers,
});

まず、Apollo Server のインスタンスを作成します。typeDefs と resolvers を渡すだけでシンプルですね。

typescript// src/index.ts(続き)

// サーバーを起動
async function startServer() {
  const { url } = await startStandaloneServer(server, {
    listen: { port: 4000 },
  });

  console.log(`🚀 Apollo Server が起動しました`);
  console.log(`${url} にアクセスしてください`);
}

// サーバー起動を実行
startServer();

startStandaloneServer 関数を使って、スタンドアロンのサーバーを起動します。非同期処理なので async/await を使用しています。

package.json のスクリプト設定

Yoga のときと同様に、開発用のスクリプトを追加します。

json{
  "scripts": {
    "dev": "ts-node src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

起動と動作確認

サーバーを起動してみましょう。

bash# 開発サーバーを起動
yarn dev

ブラウザで http:​/​​/​localhost:4000​/​ にアクセスすると、Apollo Sandbox(Apollo の GraphQL プレイグラウンド)が表示されます。

以下のクエリを試してみてください。

graphqlquery GetUsers {
  hello
  users {
    id
    name
    email
  }
}

Apollo Server では、クエリに名前を付けることが推奨されています。これにより、デバッグやモニタリングがしやすくなるのです。

図の意図:GraphQL Yoga と Apollo Server の構成の違いを比較します。

mermaidflowchart TD
  subgraph Yoga["GraphQL Yoga"]
    yoga_create["createYoga()"] --> yoga_schema["スキーマ統合"]
    yoga_schema --> yoga_http["Node.js HTTP サーバー"]
    yoga_http --> yoga_graphiql["GraphiQL 組み込み"]
  end

  subgraph Apollo["Apollo Server"]
    apollo_create["new ApolloServer()"] --> apollo_schema["スキーマ統合"]
    apollo_schema --> apollo_standalone["startStandaloneServer()"]
    apollo_standalone --> apollo_sandbox["Apollo Sandbox"]
  end

両ライブラリとも最小限の設定で動作しますが、起動方法とプレイグラウンドに違いがあります。

実装の違いと比較ポイント

GraphQL Yoga と Apollo Server の実装を比較すると、以下のような違いが見えてきます。

起動方法の違い:Yoga は createYoga() で Yoga インスタンスを作成し、それを HTTP サーバーに統合します。Apollo Server は new ApolloServer() でインスタンスを作成し、startStandaloneServer() で起動するという流れです。

プレイグラウンドの違い:Yoga はデフォルトで GraphiQL が統合されており、追加の設定なしで使えます。Apollo Server は Apollo Sandbox という独自のプレイグラウンドを提供しています。

コード量:最小構成では、どちらもほぼ同じコード量で実装できます。ただし、Yoga の方が若干シンプルな印象を受けるでしょう。

拡張性:Apollo Server は、DataSources、プラグイン、キャッシュ設定など、高度な機能を追加しやすい設計になっています。一方、Yoga は Envelop プラグインシステムを採用しており、必要な機能を柔軟に組み込めるのです。

どちらを選ぶかは、プロジェクトの要件と開発チームの経験によって決めるとよいでしょう。

まとめ

本記事では、Node.js で GraphQL サーバーを構築する際の代表的な選択肢である GraphQL Yoga と Apollo Server について、それぞれの特徴と最小構成での実装方法を解説しました。

GraphQL Yoga は、シンプルさと軽量性が特徴で、学習コストが低く、プロトタイプや小規模プロジェクトに最適です。一方、Apollo Server は、豊富な機能とエコシステムを持ち、エンタープライズレベルのアプリケーション開発に適しています。

どちらのライブラリも、最小構成であれば 100 行未満のコードで動作するサーバーを構築できることがわかりました。まずは本記事のコードを実際に動かしてみて、GraphQL サーバー開発の感覚をつかんでいただければと思います。

プロジェクトの要件に応じて最適なライブラリを選択し、段階的に機能を追加していくアプローチが、GraphQL サーバー開発の成功への近道となるでしょう。ぜひ、実際のプロジェクトで活用してみてくださいね。

関連リンク