apollo-server
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseApollo Server 5.x Guide
Apollo Server 5.x 指南
Apollo Server is an open-source GraphQL server that works with any GraphQL schema. Apollo Server 5 is framework-agnostic and runs standalone or integrates with Express, Fastify, and serverless environments.
Apollo Server是一款开源的GraphQL服务器,可与任何GraphQL模式配合使用。Apollo Server 5与框架无关,可独立运行,也可与Express、Fastify和无服务器环境集成。
Quick Start
快速开始
Step 1: Install
步骤1:安装
bash
npm install @apollo/server graphqlFor Express integration:
bash
npm install @apollo/server @as-integrations/express5 express graphql corsbash
npm install @apollo/server graphql如需与Express集成:
bash
npm install @apollo/server @as-integrations/express5 express graphql corsStep 2: Define Schema
步骤2:定义模式
typescript
const typeDefs = `#graphql
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
`;typescript
const typeDefs = `#graphql
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
`;Step 3: Write Resolvers
步骤3:编写解析器
typescript
const resolvers = {
Query: {
books: () => [
{ title: "The Great Gatsby", author: "F. Scott Fitzgerald" },
{ title: "1984", author: "George Orwell" },
],
},
};typescript
const resolvers = {
Query: {
books: () => [
{ title: "The Great Gatsby", author: "F. Scott Fitzgerald" },
{ title: "1984", author: "George Orwell" },
],
},
};Step 4: Start Server
步骤4:启动服务器
Standalone (Recommended for prototyping):
The standalone server is great for prototyping, but for production services, we recommend integrating Apollo Server with a more fully-featured web framework such as Express, Koa, or Fastify. Swapping from the standalone server to a web framework later is straightforward.
typescript
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:
typescript
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");独立模式(推荐用于原型开发):
独立服务器非常适合原型开发,但对于生产服务,我们建议将Apollo Server与功能更完善的Web框架(如Express、Koa或Fastify)集成。后续从独立服务器切换到Web框架的过程非常简单。
typescript
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集成:
typescript
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");Schema Definition
模式定义
Scalar Types
标量类型
- - 32-bit integer
Int - - Double-precision floating-point
Float - - UTF-8 string
String - - true/false
Boolean - - Unique identifier (serialized as String)
ID
- - 32位整数
Int - - 双精度浮点数
Float - - UTF-8字符串
String - - 真/假
Boolean - - 唯一标识符(序列化为字符串)
ID
Type Definitions
类型定义
graphql
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!
}graphql
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!
}Enums and Interfaces
枚举与接口
graphql
enum Status {
DRAFT
PUBLISHED
ARCHIVED
}
interface Node {
id: ID!
}
type Article implements Node {
id: ID!
title: String!
}graphql
enum Status {
DRAFT
PUBLISHED
ARCHIVED
}
interface Node {
id: ID!
}
type Article implements Node {
id: ID!
title: String!
}Resolvers Overview
解析器概述
Resolvers follow the signature:
(parent, args, contextValue, info)- parent: Result from parent resolver (root resolvers receive undefined)
- args: Arguments passed to the field
- contextValue: Shared context object (auth, dataSources, etc.)
- info: Field-specific info and schema details (rarely used)
typescript
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 });
},
},
};解析器遵循以下签名:
(parent, args, contextValue, info)- parent:父解析器的结果(根解析器接收undefined)
- args:传递给字段的参数
- contextValue:共享上下文对象(身份验证、数据源等)
- info:字段特定信息和模式详情(很少使用)
typescript
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 });
},
},
};Context Setup
上下文设置
Context is created per-request and passed to all resolvers.
typescript
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(),
},
}),
});上下文是按请求创建的,并传递给所有解析器。
typescript
interface MyContext {
token?: string;
user?: User;
dataSources: {
usersAPI: UsersDataSource;
postsAPI: PostsDataSource;
};
}
const server = new ApolloServer<MyContext>({
typeDefs,
resolvers,
});
// 独立模式
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中间件
expressMiddleware(server, {
context: async ({ req, res }) => ({
token: req.headers.authorization,
user: await getUser(req.headers.authorization),
dataSources: {
usersAPI: new UsersDataSource(),
postsAPI: new PostsDataSource(),
},
}),
});Reference Files
参考文档
Detailed documentation for specific topics:
- Resolvers - Resolver patterns and best practices
- Context and Auth - Authentication and authorization
- Plugins - Server and request lifecycle hooks
- Data Sources - RESTDataSource and DataLoader
- Error Handling - GraphQLError and error formatting
- Troubleshooting - Common issues and solutions
特定主题的详细文档:
- Resolvers - 解析器模式与最佳实践
- Context and Auth - 身份验证与授权
- Plugins - 服务器与请求生命周期钩子
- Data Sources - RESTDataSource与DataLoader
- Error Handling - GraphQLError与错误格式化
- Troubleshooting - 常见问题与解决方案
Key Rules
核心规则
Schema Design
模式设计
- Use ! (non-null) for fields that always have values
- Prefer input types for mutations over inline arguments
- Use interfaces for polymorphic types
- Keep schema descriptions for documentation
- 对始终有值的字段使用**!**(非空)
- 优先使用输入类型处理突变,而非内联参数
- 对多态类型使用接口
- 为模式添加描述以方便文档生成
Resolver Best Practices
解析器最佳实践
- Keep resolvers thin - delegate to services/data sources
- Always handle errors explicitly
- Use DataLoader for batching related queries
- Return partial data when possible (GraphQL's strength)
- 保持解析器简洁 - 将逻辑委托给服务/数据源
- 始终显式处理错误
- 使用DataLoader批量处理相关查询
- 尽可能返回部分数据(GraphQL的优势)
Performance
性能优化
- Use and
@deferfor large responses@stream - Implement DataLoader to solve N+1 queries
- Consider persisted queries for production
- Use caching headers and CDN where appropriate
- 对大型响应使用和
@defer@stream - 实现DataLoader解决N+1查询问题
- 考虑在生产环境使用持久化查询
- 适当使用缓存头和CDN
Ground Rules
基础规则
- ALWAYS use Apollo Server 5.x patterns (not v4 or earlier)
- ALWAYS type your context with TypeScript generics
- ALWAYS use from
GraphQLErrorpackage for errorsgraphql - NEVER expose stack traces in production errors
- PREFER for prototyping only
startStandaloneServer - USE an integration with a server framework like Express, Koa, Fastify, Next, etc. for production apps
- IMPLEMENT authentication in context, authorization in resolvers
- 始终使用Apollo Server 5.x的模式(而非v4或更早版本)
- 始终使用TypeScript泛型为上下文添加类型
- 始终使用包中的
graphql处理错误GraphQLError - 切勿在生产环境错误中暴露堆栈跟踪
- 仅在原型开发时优先使用
startStandaloneServer - 生产应用请使用与Express、Koa、Fastify、Next等服务器框架的集成
- 在上下文中实现身份验证,在解析器中实现授权