【免费下载链接】howtographql
The Fullstack Tutorial for GraphQL
本篇文章对应 howtographql 仓库中content/backend/graphql-js教程的 Getting Started 章节,手把手教你用 Node.js 与apollo-server从零搭建一个可运行的 GraphQL 服务器:完成项目初始化、安装依赖、编写第一份 GraphQL schema(类型定义)与对应的 resolver(解析器),并在 GraphQL Playground 中执行你的第一个查询。读完本文,你将掌握 GraphQL 服务器的最小可运行形态、schema 与 resolver 的对应关系,以及非空类型(Non-Null)在类型系统中的实际约束作用。
教程背景:schema 驱动的 Hacker News 克隆
本教程的目标是构建一个 Hacker News 克隆的 GraphQL API。与 REST 的"面向端点(endpoint)"设计不同,GraphQL 服务器只有一个统一的端点,客户端通过发送"查询(query)"来决定返回数据的结构。整个教程遵循schema-driven(schema-first)开发流程:
- 先用 GraphQL Schema Definition Language(SDL)扩展 schema 定义,加入新的根字段(root field)与对象类型;
- 再为新增字段实现对应的 resolver 函数。
在仓库的教程结构规划文件 meta/structure/express.md 中,本章节被定位为 "Getting Started",涵盖四个步骤:Defining the Schema(定义 schema)、Install Dependencies(安装依赖)、Setup Server(搭建服务器)、Testing with Playgrounds(用 Playground 测试),本文即完整呈现这一过程。
创建项目目录并初始化 package.json
教程要求你从零开始,因此第一步是创建一个存放 GraphQL 服务器的目录,并初始化 Node.js 项目。
打开终端,进入你选择的目录,然后依次执行:
mkdir hackernews-node cd hackernews-node npm init -ymkdir hackernews-node创建了项目根目录,cd hackernews-node进入其中,npm init -y则生成一个package.json文件。package.json是 Node.js 应用的配置文件,它记录应用所需的所有依赖项以及其他配置项(例如scripts脚本命令)。-y标志会让 npm 直接采用默认配置,跳过交互式提问。
创建服务器入口文件 src/index.js
接下来创建 GraphQL 服务器的入口文件index.js,它位于src目录内。
先在终端中创建src目录和空的index.js文件:
mkdir src touch src/index.js说明:教程中代码块通常带有目录或文件路径标注(例如
path=".../hackernews-node/"),表示这条终端命令应在哪个目录下执行。这种标注在仓库的渲染组件 src/components/Tutorials/Pre.tsx 中会被解析为代码块顶部的路径提示,帮助读者确定命令或代码的落点。
此刻执行node src/index.js不会产生任何输出,因为index.js还是空文件。接下来开始真正搭建 GraphQL 服务器。
安装 apollo-server 与 graphql 依赖
首先需要安装两个关键依赖:
npm install apollo-server@^2 graphql@^14.6.0关于版本有两点需要注意:
- 命令中的
@^2指定安装apollo-server的 2.x 大版本。本教程编写时基于 Apollo Server 2,教程团队计划迁移到 2021 年 7 月发布的 Apollo Server 3,但二者在使用方式上非常接近,v2 仍可顺利完成本章所有操作; graphql@^14.6.0是 GraphQL 的 JavaScript 参考实现(reference implementation),它负责 schema 校验、查询解析与执行等底层工作。
apollo-server是一个功能完备的 GraphQL 服务器,它构建在 Express.js 及若干辅助库之上,帮助你搭建可用于生产环境的 GraphQL 服务。其特性包括:
- 完全符合 GraphQL 规范(GraphQL spec-compliant);
- 通过 GraphQL subscriptions 提供实时(realtime)能力;
- 开箱即用地内置 GraphQL Playground;
- 可通过 Express 中间件进行扩展;
- 支持解析 GraphQL schema 中的自定义指令(custom directives);
- 提供查询性能追踪(query performance tracing);
- 可部署到多种环境:Vercel、Up、AWS Lambda、Heroku 等。
编写第一个 GraphQL schema 与 resolver
现在打开src/index.js,输入以下代码:
const { ApolloServer } = require('apollo-server'); // 1 const typeDefs = ` type Query { info: String! } ` // 2 const resolvers = { Query: { info: () => `This is the API of a Hackernews Clone` } } // 3 const server = new ApolloServer({ typeDefs, resolvers, }) server .listen() .then(({ url }) => console.log(`Server is running on ${url}`) );逐段理解这段代码:
typeDefs定义 GraphQL schema。这里定义了一个Query类型,其中包含一个名为info的字段,字段类型为String!。类型定义中的感叹号(!)表示该字段是**必填(required)**的,永远不能返回null;resolvers是 GraphQL schema 的实际实现。注意它的结构与typeDefs中的类型定义完全一致:Query下的info对应一个返回字符串的函数。info的 resolver 返回 Hacker News 克隆 API 的介绍文案;- 组装服务器。将 schema 与 resolvers 一并传给从
apollo-server导入的ApolloServer构造函数,告诉服务器"接受哪些 API 操作、这些操作如何被解析(resolve)"。最后调用server.listen()启动服务器,并在回调中打印监听地址。
说明:
src/index.js同时使用了typeDefs(schema 字符串)与resolvers(实现对象),这种"schema 声明 + resolver 实现"的双层结构正是 GraphQL 服务器的核心组织方式,后续章节在此基础上不断扩充两者即可持续增加 API 能力。
启动服务器并用 GraphQL Playground 测试
在项目根目录执行:
node src/index.js终端会提示服务器运行在http://localhost:4000。用浏览器打开该地址,你会看到GraphQL Playground——一个交互式的 "GraphQL IDE",可以像使用 Postman 之于 REST 那样,交互式地探索 API 的能力。它具备以下能力:
- 根据 schema 自动生成所有 API 操作的完整文档;
- 提供带有自动补全与语法高亮的编辑器,可以编写查询、变更与订阅;
- 方便地分享 API 操作。
点击右侧的DOCS按钮可以打开 API 文档:这份文档由 schema 定义自动生成,展示 schema 中所有的 API 操作与数据类型。
现在发送你的第一个 GraphQL 查询。在左侧编辑区输入:
query { info }点击中间的Play按钮(Mac 上也可用CMD+ENTER,Windows/Linux 上为CTRL+ENTER)将查询发送给服务器。服务器会返回info字段对应的字符串。至此,你已经实现并成功测试了第一个 GraphQL 查询。
验证非空类型约束:返回 null 会发生什么
前面提到info: String!中的感叹号意味着该字段永远不能为null。由于 resolver 的实现权在你手上,不妨验证一下:如果把 resolver 改成返回null,会发生什么?
将index.js中resolvers的定义更新为:
const resolvers = { Query: { info: () => null, } }修改后需要重启服务器:先用CTRL+C停止,再执行node src/index.js。重新发送之前的查询,这次会得到一个错误:
Error: Cannot return null for non-nullable field Query.info.背后的原理是:底层的graphql-js参考实现会确保 resolver 的返回类型与 GraphQL schema 中的类型定义保持一致。换句话说,类型系统替你拦截了"愚蠢的错误"。这正是 GraphQL 的核心价值之一:它强制 API 的行为与 schema 定义所承诺的行为一致。任何能访问 GraphQL schema 的人,都可以 100% 确定 API 的操作与返回的数据结构。
理解 GraphQL schema:SDL 与根类型
每个 GraphQL API 的核心都是一份 GraphQL schema。GraphQL schema 通常使用Schema Definition Language(SDL)编写。SDL 拥有自己的类型系统,可以像 Java、TypeScript、Swift、Go 等强类型语言一样定义数据结构。仓库中的基础概念章节 content/graphql/basics/2-core-concepts.md 对 SDL 有更系统的讲解,例如:
type Person { name: String! age: Int! }每个 GraphQL schema 都有三个特殊的根类型(root types):Query、Mutation和Subscription,它们分别对应 GraphQL 的三种操作类型:查询、变更、订阅。根类型上的字段被称为根字段(root fields),它们定义了 API 可用的操作。
从简单 schema 说起
考虑上文使用的简单 schema:
type Query { info: String! }该 schema 只有一个根字段info。向 GraphQL API 发送查询、变更或订阅时,操作总是以根字段开头。这里只有一个根字段,因此 API 只接受一种查询。
进阶示例:对象类型、selection set 与类型修饰符
再看一个稍微进阶的例子:
type Query { users: [User!]! user(id: ID!): User } type Mutation { createUser(name: String!): User! } type User { id: ID! name: String! }这里有三个根字段:Query上的users与user,以及Mutation上的createUser。User类型必须额外定义,否则 schema 定义是不完整的。
由此可以推导出该 API 接受哪些操作。之前info字段的类型是String——一种标量类型(scalar type);而当根字段的类型本身是另一个**对象类型(object type)**时,你可以在查询(或变更/订阅)中用该对象类型的字段进一步展开,展开的部分称为selection set(选择集)。
实现上述 schema 的 API 接受如下操作:
# 查询所有用户 query { users { id name } } # 按 id 查询单个用户 query { user(id: "user-1") { id name } } # 创建一个新用户 mutation { createUser(name: "Bob") { id name } }这里有几个值得注意的要点:
- 上面的例子都查询了返回的
User对象的id和name,你也可以省略其中任意一个;但当查询对象类型时,selection set 中至少要查询该对象的一个字段; - 对于 selection set 中的字段而言,根字段的类型是"必填"还是"列表"并不影响书写方式。上述三个根字段对
User类型应用了不同的类型修饰符(type modifiers):users的返回类型[User!]!:返回一个列表(列表本身不能为null),且列表中不允许包含null元素。也就是说,你拿到的要么是空列表,要么是只包含非空User对象的列表;user(id: ID!)的返回类型User:返回值可以是null,也可以是User对象;createUser(name: String!)的返回类型User!:该操作总是返回一个User对象。
下一步:从最小服务器走向完整 API
本章完成的是一个"最小可运行"的 GraphQL 服务器。在后续章节中,你会沿着同样的 schema-driven 流程持续演进:
- 在 2-a-simple-query.md 中新增
feed根字段与Link对象类型,实现 Hacker News 的链接流查询,并理解 resolver 的四参数签名(其中第一个参数parent是上一层 resolver 的返回值)以及"查询解析 = 编排 resolver 调用"的机制; - 在 3-a-simple-mutation.md 中新增
post变更,学习 resolver 的第二个参数args(携带操作的入参,如url与description),并把 schema 抽取到独立的src/schema.graphql文件,通过fs.readFileSync读取; - 之后再为服务器接入数据库、认证、过滤与分页等能力,最终形成一个完整的 Hacker News 克隆 API。
这些章节共同构成仓库中 graphql-js 教程 的完整技术栈:Apollo Server 2 负责 GraphQL 服务器,graphql-js提供底层解析与校验,Prisma 负责数据库访问,GraphQL Playground 负责交互式调试。
【免费下载链接】howtographql
The Fullstack Tutorial for GraphQL
相关推荐
HowToGraphQL 后端实战(一):用 TypeScript、Apollo Server 与 Nexus 从零搭建第一个 GraphQL 服务
HowToGraphQL 后端实战(一):用 TypeScript、Apollo Server 与 Nexus 从零搭建第一个 GraphQL 服务 本篇是 H
HowToGraphQL 之 TypeScript + Apollo Server 全栈 GraphQL 服务实战总结:从零搭建到生产部署
HowToGraphQL 之 TypeScript + Apollo Server 全栈 GraphQL 服务实战总结:从零搭建到生产部署 本篇是 HowToG
How to GraphQL 实战:用 Node.js、Apollo Server 与 Prisma 从零构建完整 GraphQL 服务器
How to GraphQL 实战:用 Node.js、Apollo Server 与 Prisma 从零构建完整 GraphQL 服务器 本指南以 conte
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考