🧩 一、概览:Next.js + GraphQL 是怎么"对话"的?
Next.js 是前后端一体框架,而 GraphQL 是一种 API 查询语言。结合起来后:
🤝 Next.js 提供运行环境 ,
🧠 GraphQL 提供数据语义接口。
简单理解:
- Next.js = 舞台和播放器(API 路径、页面渲染、Serverless 运行)
- GraphQL = 剧本(Schema定义)、演员台词逻辑(Resolver)、导演策略(Context)
结构大致如下:
scss
Next.js API Route ─┬─► ApolloServer / Yoga Server
│
└─► GraphQL Schema (定义数据结构)
└─► Resolver (具体处理逻辑)
└─► Context (跨请求共享上下文)
🧱 二、Schema:GraphQL 的"数据契约"
Schema 是 定义数据形状的语言模型 。
可以把它理解为数据库表结构 + API 文档的结合体。
示例 ⚙️
bash
# ./graphql/schema.graphql
type User {
id: ID!
name: String!
age: Int
}
type Query {
users: [User!]!
user(id: ID!): User
}
type Mutation {
addUser(name: String!, age: Int): User
}
📘 要点笔记:
type:定义类型(用户、文章、评论等)Query:读取数据的入口Mutation:修改、创建、删除数据的入口
Schema 就像一份菜单,它定义了服务员能做的所有菜,但不做菜。
做菜的是 Resolver 👉
🧠 三、Resolver:GraphQL 的"大脑中枢"
Resolver 是 Schema 的执行器 ,它负责将查询请求映射到实际数据源 。
在 Next.js 中,一般写成 JS/TS 文件与 Schema 匹配。
示例 👇
javascript
// ./graphql/resolvers.js
const users = [
{ id: "1", name: "Neo", age: 29 },
{ id: "2", name: "Trinity", age: 27 },
];
export const resolvers = {
Query: {
users: () => users,
user: (_, { id }) => users.find(u => u.id === id),
},
Mutation: {
addUser: (_, { name, age }) => {
const newUser = { id: String(users.length + 1), name, age };
users.push(newUser);
return newUser;
},
},
};
📘 要点笔记:
- 每个字段对应一个函数。
- 第一个参数
_通常是父级字段(这里未使用,可省略)。 - 第二个参数
{ id }是客户端传入的变量。 - Resolver 内不管 Schema 长啥样,它只需返回对应数据。
🌍 四、Context:连接"每个请求"的神经系统
Context 是 GraphQL 在请求周期中共享的环境对象 。
它的作用类似于:
- 注入依赖(数据库实例、token 验证、用户状态)
- 跨 Resolver 共享状态
示例:
javascript
import jwt from "jsonwebtoken";
import db from "./db.js";
export const createContext = ({ req }) => {
const token = req.headers.authorization || "";
let user = null;
try {
user = jwt.verify(token, process.env.JWT_SECRET);
} catch (e) {
console.log("token 无效或未提供");
}
return { db, user };
};
在 Resolver 中,就能这样访问:
javascript
Mutation: {
addUser: (_, { name, age }, { db, user }) => {
if (!user) throw new Error("未授权");
return db.insertUser({ name, age });
}
}
📘 要点笔记:
- Context 在每次请求开始时创建(一次请求一次 Context)。
- 经 Context 可安全访问外部资源且隔离状态。
- 在 SSR 和 Serverless 模式的 Next.js 中非常实用。
⚙️ 五、在 Next.js 中整合 Apollo Server
在 Next.js 中最常见的方式是用 /api/graphql 作为后端入口。
javascript
// ./pages/api/graphql.js
import { ApolloServer } from "apollo-server-micro";
import { typeDefs } from "../../graphql/schema.js";
import { resolvers } from "../../graphql/resolvers.js";
import { createContext } from "../../graphql/context.js";
const server = new ApolloServer({
typeDefs,
resolvers,
context: createContext,
});
export const config = {
api: { bodyParser: false },
};
export default server.createHandler({ path: "/api/graphql" });
💡 运行逻辑:
- 浏览器访问
/api/graphql - Next.js 调用 ApolloServer 处理请求
- ApolloServer 根据 Schema 调用对应 Resolver
- Resolver 通过 Context 访问数据源
- 返回 JSON 响应
🖥️ 六、Next.js 前端调用示例
javascript
import { gql, useQuery } from "@apollo/client";
const ALL_USERS = gql`
query {
users {
id
name
age
}
}
`;
export default function UsersList() {
const { loading, error, data } = useQuery(ALL_USERS);
if (loading) return <p>⏳ 加载中...</p>;
if (error) return <p>❌ 出错啦: {error.message}</p>;
return (
<ul>
{data.users.map(u => (
<li key={u.id}>
👤 {u.name}(年龄:{u.age ?? "未知"})
</li>
))}
</ul>
);
}
在这里,前端只需声明「我想要什么」,
后端就帮你搞定「怎么算出来」。
💬 七、小结:三大组件一图流
arduino
<div style="max-width:720px;margin:auto;text-align:center;">
<svg width="100%" height="300" viewBox="0 0 720 300" xmlns="http://www.w3.org/2000/svg">
<rect x="60" y="60" width="170" height="60" rx="10" fill="#A1C4FD" stroke="#333"/>
<text x="145" y="95" text-anchor="middle" font-size="13">Schema (定义契约)</text>
<rect x="280" y="60" width="170" height="60" rx="10" fill="#FDD692" stroke="#333"/>
<text x="365" y="95" text-anchor="middle" font-size="13">Resolver (处理逻辑)</text>
<rect x="500" y="60" width="170" height="60" rx="10" fill="#C2E9FB" stroke="#333"/>
<text x="585" y="95" text-anchor="middle" font-size="13">Context (执行环境)</text>
<line x1="230" y1="90" x2="280" y2="90" stroke="#000" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="450" y1="90" x2="500" y2="90" stroke="#000" stroke-width="2" marker-end="url(#arrow)"/>
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="6" refY="3" orient="auto">
<path d="M0,0 L0,6 L9,3 z" fill="#333"/>
</marker>
</defs>
</svg>
<p style="font-size:13px;color:#666;">▲ Next.js GraphQL 三件套结构关系图</p>
</div>
🚀 八、为什么 Next.js 是 GraphQL 的理想宿主?
- Serverless Ready:API 路由天然适合部署 Apollo 或 Yoga Server。
- SSR + CSR 混合渲染:可直连 GraphQL 数据,从后端直出页面。
- Edge Runtime:未来的 Web AGI 场景(边缘智能体)可直接调用 GraphQL 层。
- TypeScript 一体化支持:Schema + Resolver 均能生成类型定义,开发丝滑。