今回やること
Apollo Server 5で、次の2つだけを持つGraphQL APIを作ります。
- 誰でも表示名を読める
publicProfileQuery - 認証された本人の表示名だけを変える
updateMyDisplayNameMutation
学習用のメモリーデータを使うため、データベースは不要です。GraphQLの基本構造と、認証情報をMutationへ渡す境界に集中します。

前提条件
- Node.js 20以上
- npmが使える
- TypeScriptの関数とオブジェクトが読める
Apollo Server 5はNode.js 20以上を必要とします。次のコマンドで確認してください。
node --version
npm --version
プロジェクトを準備する
mkdir graphql-profile-api
cd graphql-profile-api
npm init -y
npm install @apollo/server graphql
npm install --save-dev typescript tsx @types/node
mkdir src
package.jsonへtypeとdevスクリプトを追加します。
{
"name": "graphql-profile-api",
"private": true,
"type": "module",
"scripts": {
"dev": "tsx src/index.ts"
},
"dependencies": {
"@apollo/server": "^5.0.0",
"graphql": "^16.11.0"
},
"devDependencies": {
"@types/node": "^24.0.0",
"tsx": "^4.0.0",
"typescript": "^5.0.0"
}
}
npm installが作った正確なバージョンは環境によって異なります。手入力で上書きせず、そのまま使って構いません。
APIを実装する
src/index.tsを作成します。
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { GraphQLError } from "graphql";
type User = {
id: string;
displayName: string;
email: string;
};
type GraphQLContext = {
userId: string | null;
};
const users = new Map<string, User>([
[
"user-1",
{
id: "user-1",
displayName: "Ada",
email: "ada@example.com",
},
],
]);
const typeDefs = `#graphql
type PublicProfile {
id: ID!
displayName: String!
}
type Query {
publicProfile(id: ID!): PublicProfile
}
type Mutation {
updateMyDisplayName(displayName: String!): PublicProfile!
}
`;
const resolvers = {
Query: {
publicProfile: (
_parent: unknown,
{ id }: { id: string },
): User | null => users.get(id) ?? null,
},
Mutation: {
updateMyDisplayName: (
_parent: unknown,
{ displayName }: { displayName: string },
context: GraphQLContext,
): User => {
if (context.userId === null) {
throw new GraphQLError("Authentication required", {
extensions: { code: "UNAUTHENTICATED" },
});
}
const user = users.get(context.userId);
if (user === undefined) {
throw new GraphQLError("User not found", {
extensions: { code: "NOT_FOUND" },
});
}
const normalizedName = displayName.trim();
if (normalizedName.length < 1 || normalizedName.length > 30) {
throw new GraphQLError("Display name must be 1 to 30 characters", {
extensions: { code: "BAD_USER_INPUT" },
});
}
user.displayName = normalizedName;
return user;
},
},
};
const server = new ApolloServer<GraphQLContext>({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
context: async ({ req }) => {
const authorization = req.headers.authorization;
// 学習用: この固定tokenをuser-1という本人に対応させる
const userId =
authorization === "Bearer learning-token" ? "user-1" : null;
return { userId };
},
});
console.log(`Server ready at ${url}`);
この例で重要なのは次の3点です。
- GraphQLへ公開する
PublicProfileにemailを含めない - Mutationの引数でユーザーIDを受け取らず、認証結果の
context.userIdを使う - 認証後も入力値を検証する
固定トークンとメモリーデータは学習用です。本番では、署名を検証したセッションやアクセストークンからsubject(利用者ID)を決め、永続データベースを更新します。
成功を確認する
サーバーを起動します。
npm run dev
別のターミナルから公開Queryを送ります。
curl http://localhost:4000/ \
-H 'content-type: application/json' \
--data '{"query":"query { publicProfile(id: \"user-1\") { id displayName } }"}'
次のように表示されれば成功です。
{"data":{"publicProfile":{"id":"user-1","displayName":"Ada"}}}
次に、認証付きMutationを送ります。
curl http://localhost:4000/ \
-H 'content-type: application/json' \
-H 'authorization: Bearer learning-token' \
--data '{"query":"mutation { updateMyDisplayName(displayName: \"Ada Lovelace\") { id displayName } }"}'
{"data":{"updateMyDisplayName":{"id":"user-1","displayName":"Ada Lovelace"}}}
authorizationヘッダーを外して同じMutationを送ると、UNAUTHENTICATEDエラーになります。公開Queryの結果にemailが出ないことも確認してください。
よくあるエラー
Node.jsのバージョンが古い
Apollo Server 5はNode.js 20以上が必要です。node --versionを確認し、古ければ更新します。
Cannot find packageと表示される
プロジェクト直下で依存関係を入れ直します。
npm install
MutationがUNAUTHENTICATEDになる
ヘッダーがauthorization: Bearer learning-tokenになっているか確認します。Bearerの後ろには半角スペースが1つ必要です。
練習
表示名の最大文字数を20文字へ変え、21文字のMutationがBAD_USER_INPUTになることを確認してください。
次のステップ
この例を理解したら、固定トークンを本物の認証処理へ置き換えます。先にJWTの仕組みを読み、署名検証とsubjectの扱いを確認してください。
参考リソース
- Apollo Server: Get started
- Apollo Server: startStandaloneServer
- Apollo Server 5への移行
- GraphQL: Authentication and authorization
(最終確認: 2026年7月25日)
← 一覧に戻る