关于 apollo-server
面向使用 Apollo Server 5.x 构建 GraphQL 服务的指南技能,涵盖 Schema、Resolver、请求上下文与部署方式,适合实现 GraphQL API 的开发者。
主要功能
- 01Apollo Server 5.x 配置
- 02Schema 与 Resolver 指南
- 03按请求设置上下文
- 04独立运行与框架集成
适用场景
- 01快速搭建 GraphQL API 原型
- 02设计 Resolver 和请求上下文
- 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 集成到功能更完善的 Web 框架中,例如 Express、Koa 或 Fastify。之后从独立服务切换到 Web 框架很简单。
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 和错误格式化
- 故障排除 - 常见问题和解决方案
关键规则
架构设计
- 对始终有值的字段使用 !(非空)
- 对变更优先使用输入类型,而非内联参数
- 对多态类型使用接口
- 保留架构描述以供文档使用
解析器最佳实践
- 保持解析器精简——将工作委托给服务/数据源
- 始终显式处理错误
- 使用 DataLoader 批量处理相关查询
- 尽可能返回部分数据(这是 GraphQL 的优势)
性能
- 对大型响应使用
@defer和@stream - 使用 DataLoader 解决 N+1 查询问题
- 考虑在生产环境中使用持久化查询
- 适当地使用缓存标头和 CDN
基本规则
- 始终使用 Apollo Server 5.x 模式(不要使用 v4 或更早版本)
- 始终使用 TypeScript 泛型为上下文指定类型
- 始终使用
graphql包中的GraphQLError处理错误 - 绝不要在生产环境的错误中暴露堆栈跟踪
- 原型开发时优先使用
startStandaloneServer - 生产应用应集成 Express、Koa、Fastify、Next 等服务框架
- 在上下文中实现身份验证,在解析器中实现授权
评论
支持 Markdown