3、搭建GraphQL服务端:使用Apollo Server快速搭建一个GraphQL服务端
好,咱们直接进入正题。这一章我们要亲手搭一个GraphQL服务端出来。你可能会想:「又要配环境?又要装一堆依赖?」别担心,Apollo Server 把这活儿简化得相当彻底。我当年第一次搭的时候,从零到跑通第一个查询,也就花了十分钟。
3.1 为什么选 Apollo Server?
市面上 GraphQL 服务端的实现有好几种,比如 graphql-yoga、Express GraphQL 等等。但我个人习惯用 Apollo Server,原因很简单:
- 开箱即用——不需要手动集成 Express 或 Koa
- 生态成熟——缓存、订阅、联邦等功能都有官方支持
- 文档清晰——遇到问题查起来不费劲
说白了,Apollo Server 就是 GraphQL 服务端里的「瑞士军刀」。你不需要纠结底层细节,把精力放在业务逻辑上就好。
3.2 初始化项目
先创建一个新目录,然后初始化 npm 项目:
mkdir graphql-server-demo
cd graphql-server-demo
npm init -y
嗯,这里要注意:npm init -y 会生成一个默认的 package.json。如果你想自定义,也可以不加 -y 手动填写。
3.3 安装依赖
接下来安装核心包:
npm install @apollo/server graphql
就两个包?对,就两个。@apollo/server 是 Apollo Server 4.x 的包名,graphql 是 GraphQL 的 JavaScript 参考实现。我在项目中遇到过有人多装了一堆没用的中间件,其实完全没必要。
apollo-server。4.x 改成了 @apollo/server,API 也有变化。建议直接用最新的 4.x。
3.4 编写第一个 GraphQL Schema
Schema 是 GraphQL 的核心。它定义了客户端能查什么、怎么查。我们来定义一个简单的图书查询:
// schema.js
const typeDefs = `#graphql
type Book {
id: ID!
title: String!
author: String!
}
type Query {
books: [Book]
book(id: ID!): Book
}
`;
你想想看,这个 Schema 告诉客户端两件事:
- 有一个
Book类型,包含 id、title、author 三个字段 - 有两个查询入口:获取所有图书、根据 ID 获取单本图书
#graphql 这个注释不是随便写的。它告诉代码编辑器(比如 VS Code 的 GraphQL 插件)「下面这段是 GraphQL 语法」,从而获得语法高亮。这个小技巧是我从 Apollo 官方示例里学来的。
3.5 编写 Resolver
Schema 只是「声明」,Resolver 才是「实现」。它告诉 Apollo Server 每个字段的数据从哪里来:
// resolvers.js
const books = [
{ id: '1', title: 'GraphQL 入门', author: '张三' },
{ id: '2', title: 'React 实战', author: '李四' },
];
const resolvers = {
Query: {
books: () => books,
book: (parent, args) => books.find(b => b.id === args.id),
},
};
这里我用的是内存数据,实际项目中你会换成数据库查询。不过原理一样——Resolver 就是一个函数,返回对应字段的值。
args 包含了客户端传过来的参数。比如查询 book(id: "1") 时,args.id 就是 "1"。我曾经犯过一个低级错误:忘了把 id 转成数字类型,结果死活查不到数据。
3.6 启动服务端
最后一步,把 Schema 和 Resolver 组装起来,启动服务:
// index.js
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { typeDefs } from './schema.js';
import { resolvers } from './resolvers.js';
const server = new ApolloServer({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
});
console.log(`🚀 服务已启动:${url}`);
运行 node index.js,你会看到控制台输出:
🚀 服务已启动:http://localhost:4000/
打开浏览器访问这个地址,你会看到 Apollo Sandbox——一个在线的 GraphQL 查询工具。你可以直接在页面上写查询语句,测试你的 API。
3.7 测试查询
在 Apollo Sandbox 里输入:
query {
books {
id
title
author
}
}
点击运行,你会得到:
{
"data": {
"books": [
{ "id": "1", "title": "GraphQL 入门", "author": "张三" },
{ "id": "2", "title": "React 实战", "author": "李四" }
]
}
}
看到这个结果,说明你的 GraphQL 服务端已经跑起来了。是不是很简单?
3.8 常见问题与避坑
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 端口被占用 | 4000 端口已被其他程序使用 | 修改 listen.port 为其他端口,比如 4001 |
| Schema 语法错误 | 类型定义中漏了括号或逗号 | 检查 typeDefs 中的 GraphQL 语法,可以用 graphql 包的 parse 函数验证 |
| Resolver 返回 undefined | 字段名拼写错误或数据源中没有该字段 | 检查 Resolver 函数名是否与 Schema 中的字段名一致 |
3.9 下一步做什么?
现在你有了一个能跑的服务端。但说实话,这只是冰山一角。接下来我们会:
- 接入真实数据库(比如 MongoDB 或 PostgreSQL)
- 处理 Mutation(增删改操作)
- 添加认证和权限控制
不过别急,先把今天的内容消化掉。自己动手搭一遍,遇到问题别怕——我当年第一次搭的时候,光端口冲突就折腾了半小时。这些都是成长的一部分。
好,这一章就到这儿。下一章我们聊聊「如何用 GraphQL 查询数据」,到时候你会看到客户端怎么跟这个服务端交互。