apollo-server について
Apollo Server 5.x で GraphQL サーバーを構築するためのガイドスキルです。スキーマ、リゾルバー、リクエストコンテキスト、デプロイ方法を扱い、GraphQL API の実装に役立ちます。
主な機能
- 01Apollo Server 5.x の設定
- 02スキーマとリゾルバーの指針
- 03リクエスト単位のコンテキスト
- 04単独実行とフレームワーク連携
活用シーン
- 01GraphQL API のプロトタイプ作成
- 02リゾルバーとコンテキストの設計
- 03本番向けサーバー連携の選択
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ apollographql/ skills --skill apollo-serverインストール後、Claude Code で/apollo-serverを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/context-and-auth.mddata-sources.mderror-handling.mdplugins.mdresolvers.mdtroubleshooting.md詳細
Apollo Server 5.x ガイド
Apollo Server は、あらゆる GraphQL スキーマで動作するオープンソースの GraphQL サーバーです。Apollo Server 5 はフレームワークに依存せず、スタンドアロンで動作するほか、Express、Fastify、サーバーレス環境と統合できます。
クイックスタート
ステップ 1:インストール
npm install @apollo/server graphql
Express との統合の場合:
npm install @apollo/server @as-integrations/express5 express graphql cors
ステップ 2:スキーマを定義する
const typeDefs = `#graphql
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
`;
ステップ 3:リゾルバーを作成する
const resolvers = {
Query: {
books: () => [
{ title: "The Great Gatsby", author: "F. Scott Fitzgerald" },
{ title: "1984", author: "George Orwell" },
],
},
};
ステップ 4:サーバーを起動する
スタンドアロン(プロトタイピングにおすすめ):
スタンドアロンサーバーはプロトタイピングに最適ですが、本番サービスでは、Apollo Server を Express、Koa、Fastify などのより高機能なウェブフレームワークと統合することをおすすめします。後からスタンドアロンサーバーをウェブフレームワークに切り替えるのは簡単です。
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
const server = new ApolloServer({ typeDefs, resolvers });
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
});
console.log(`Server ready at ${url}`);
Express:
import { ApolloServer } from "@apollo/server";
import { expressMiddleware } from "@as-integrations/express5";
import { ApolloServerPluginDrainHttpServer } from "@apollo/server/plugin/drainHttpServer";
import express from "express";
import http from "http";
import cors from "cors";
const app = express();
const httpServer = http.createServer(app);
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});
await server.start();
app.use(
"/graphql",
cors(),
express.json(),
expressMiddleware(server, {
context: async ({ req }) => ({ token: req.headers.authorization }),
}),
);
await new Promise<void>((resolve) => httpServer.listen({ port: 4000 }, resolve));
console.log("Server ready at http://localhost:4000/graphql");
スキーマ定義
スカラー型
Int- 32 ビット整数Float- 倍精度浮動小数点数String- UTF-8 文字列Boolean- true/falseID- 一意の識別子(String としてシリアライズされます)
型定義
type User {
id: ID!
name: String!
email: String
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String
author: User!
}
input CreatePostInput {
title: String!
content: String
}
type Query {
user(id: ID!): User
users: [User!]!
}
type Mutation {
createPost(input: CreatePostInput!): Post!
}
列挙型とインターフェース
enum Status {
DRAFT
PUBLISHED
ARCHIVED
}
interface Node {
id: ID!
}
type Article implements Node {
id: ID!
title: String!
}
リゾルバーの概要
リゾルバーのシグネチャは次のとおりです:(parent, args, contextValue, info)
- parent:親リゾルバーの結果(ルートリゾルバーでは undefined が渡されます)
- args:フィールドに渡される引数
- contextValue:共有コンテキストオブジェクト(認証、dataSources など)
- info:フィールド固有の情報とスキーマの詳細(通常は使用しません)
const resolvers = {
Query: {
user: async (_, { id }, { dataSources }) => {
return dataSources.usersAPI.getUser(id);
},
},
User: {
posts: async (parent, _, { dataSources }) => {
return dataSources.postsAPI.getPostsByAuthor(parent.id);
},
},
Mutation: {
createPost: async (_, { input }, { dataSources, user }) => {
if (!user) throw new GraphQLError("Not authenticated");
return dataSources.postsAPI.create({ ...input, authorId: user.id });
},
},
};
コンテキストの設定
コンテキストはリクエストごとに作成され、すべてのリゾルバーに渡されます。
interface MyContext {
token?: string;
user?: User;
dataSources: {
usersAPI: UsersDataSource;
postsAPI: PostsDataSource;
};
}
const server = new ApolloServer<MyContext>({
typeDefs,
resolvers,
});
// Standalone
const { url } = await startStandaloneServer(server, {
context: async ({ req }) => ({
token: req.headers.authorization || "",
user: await getUser(req.headers.authorization || ""),
dataSources: {
usersAPI: new UsersDataSource(),
postsAPI: new PostsDataSource(),
},
}),
});
// Express middleware
expressMiddleware(server, {
context: async ({ req, res }) => ({
token: req.headers.authorization,
user: await getUser(req.headers.authorization),
dataSources: {
usersAPI: new UsersDataSource(),
postsAPI: new PostsDataSource(),
},
}),
});
参照ファイル
トピック別の詳細なドキュメント:
- リゾルバー - リゾルバーのパターンとベストプラクティス
- コンテキストと認証 - 認証と認可
- プラグイン - サーバーとリクエストのライフサイクルフック
- データソース - RESTDataSource と DataLoader
- エラー処理 - GraphQLError とエラーのフォーマット
- トラブルシューティング - よくある問題と解決策
重要なルール
スキーマ設計
- 常に値があるフィールドには !(非 null)を使用します
- ミューテーションではインライン引数より入力型を優先します
- 多態的な型にはインターフェースを使用します
- ドキュメント用にスキーマの説明を残します
リゾルバーのベストプラクティス
- リゾルバーは薄く保ち、サービス/データソースに処理を委任します
- エラーは必ず明示的に処理します
- 関連するクエリのバッチ処理には DataLoader を使用します
- 可能な場合は部分データを返します(GraphQL の強みです)
パフォーマンス
- 大きなレスポンスには
@deferと@streamを使用します - DataLoader を実装して N+1 クエリを解消します
- 本番環境では永続化クエリを検討します
- 適切な場合はキャッシュヘッダーと CDN を使用します
基本ルール
- 必ず Apollo Server 5.x のパターンを使用します(v4 以前のものは使用しません)
- 必ず TypeScript のジェネリクスでコンテキストに型を指定します
- エラーには必ず
graphqlパッケージのGraphQLErrorを使用します - 本番環境のエラーではスタックトレースを決して公開しません
- プロトタイピングに限り、
startStandaloneServerを優先します - 本番アプリでは Express、Koa、Fastify、Next などのサーバーフレームワークとの統合を使用します
- コンテキストで認証を、リゾルバーで認可を実装します
コメント
Markdown 対応