mcpField
A
apollo-server

apollo-server

github.com/apollographql开发1212.9k 次安装1 天前更新
代码仓库

关于 apollo-server

面向使用 Apollo Server 5.x 构建 GraphQL 服务的指南技能,涵盖 Schema、Resolver、请求上下文与部署方式,适合实现 GraphQL API 的开发者。

主要功能

  1. 01Apollo Server 5.x 配置
  2. 02Schema 与 Resolver 指南
  3. 03按请求设置上下文
  4. 04独立运行与框架集成

适用场景

  1. 01快速搭建 GraphQL API 原型
  2. 02设计 Resolver 和请求上下文
  3. 03选择生产环境服务器集成方式

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/apollographql/skills --skill apollo-server

安装后在 Claude Code 中输入/apollo-server确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
context-and-auth.md
data-sources.md
error-handling.md
plugins.md
resolvers.md
troubleshooting.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/false
  • ID - 唯一标识符(序列化为 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(),
    },
  }),
});

参考文件

特定主题的详细文档:

关键规则

架构设计
  • 对始终有值的字段使用 !(非空)
  • 对变更优先使用输入类型,而非内联参数
  • 对多态类型使用接口
  • 保留架构描述以供文档使用
解析器最佳实践
  • 保持解析器精简——将工作委托给服务/数据源
  • 始终显式处理错误
  • 使用 DataLoader 批量处理相关查询
  • 尽可能返回部分数据(这是 GraphQL 的优势)
性能
  • 对大型响应使用 @defer 和 @stream
  • 使用 DataLoader 解决 N+1 查询问题
  • 考虑在生产环境中使用持久化查询
  • 适当地使用缓存标头和 CDN

基本规则

  • 始终使用 Apollo Server 5.x 模式(不要使用 v4 或更早版本)
  • 始终使用 TypeScript 泛型为上下文指定类型
  • 始终使用 graphql 包中的 GraphQLError 处理错误
  • 绝不要在生产环境的错误中暴露堆栈跟踪
  • 原型开发时优先使用 startStandaloneServer
  • 生产应用应集成 Express、Koa、Fastify、Next 等服务框架
  • 在上下文中实现身份验证,在解析器中实现授权

评论

支持 Markdown