✏️ 让我们定义该架构
打开我们的 IDE 并检出 Catstronauts 项目,然后导航到server/src/
目录。在该目录中,我们将创建一个新的schema.js
文件。
为了开始构建我们的架构,我们首先需要几个包: @apollo/server
, graphql
以及 graphql-tag
。
- The
@apollo/server
包提供了一个完整的、符合规范的 GraphQL 服务器。 - The
graphql
包提供了解析和验证 GraphQL 查询的核心逻辑。 - The
graphql-tag
包提供了gql
模板字面量,我们将在稍后使用它。
从 server/
目录运行以下命令:
npm install @apollo/server graphql graphql-tag
现在在 schema.js
中,让我们从 graphql-tag
获取 gql
模板字面量:
const gql = require("graphql-tag");
我们导入的这个 gql
是什么?它是一个带标签的模板字面量,用于包装 GraphQL 字符串,例如我们即将编写的架构定义。
这会将 GraphQL 字符串转换为 Apollo 库在处理 操作 和架构时所期望的格式,并且它还支持语法高亮显示。
接下来,让我们声明一个 typeDefs
(代表“类型定义”)常量,并为其分配 gql
模板,我们的定义将存储在该模板中。同时,我们现在将导出 typeDefs
,因为我们稍后会在服务器文件中使用它。
const typeDefs = gql`# Schema definitions go here`;module.exports = typeDefs;
请注意,我们使用反引号(`
)与 gql
标签一起使用,不要与单引号('
)混淆。
很好,我们已经准备好定义我们的类型了。参考我们的模型,我们确定每个学习轨道的以下数据是必要的
- 标题
- 缩略图
- 时长
- 模块数量
- 作者姓名
- 作者照片
我们如何将这些数据组织成类型?
我们可以创建一个名为 Track
的单个类型,将所有这些 字段 放入其中,然后结束。但从业务领域的角度来看,这样合理吗?不尽然。首先,一个作者可能会创建多个轨道,并且该作者的信息会在多个位置进行不必要的重复。相反,我们需要从独立实体的角度考虑。我们将从两个实体开始: Track
和 Author
。
Track
类型
我们将从 Track
类型开始,该类型表示特定的学习轨道。让我们定义该类型并立即添加描述:
"A track is a group of Modules that teaches about a specific topic"type Track {# Fields go here}
现在对于轨道的 字段,我们将使用:
id
类型为ID!
title
类型为String!
author
类型为Author!
(我们将在完成Track
后定义Author
类型)thumbnail
类型为String
(轨道卡片的图像 URL)length
类型为Int
modulesCount
类型为Int
这是完整的 Track
类型:
"A track is a group of Modules that teaches about a specific topic"type Track {id: ID!title: String!author: Author!thumbnail: Stringlength: IntmodulesCount: Int}
我们如何确定这些 字段 中哪些应该允许为 null?一种方法是让架构反映我们的“业务”领域规则。例如,轨道可能存在而没有缩略图,但从我们的“业务”角度来看,没有标题或作者的轨道是没有意义的。
为这些 字段 添加一些不错的描述,然后让我们继续使用 Author
类型。
Author
类型
"Author of a complete Track or a Module"type Author {# Fields go here}
The Author
类型只包含三个 字段:
id
类型为ID!
name
类型为String!
photo
类型为String
这是完整的类型
"Author of a complete Track or a Module"type Author {id: ID!name: String!photo: String}
太好了,我们的第一个功能现在已完全体现在我们的架构中。这些是我们能够检索的数据类型。
不过,我们还缺少一个部分:如何告诉 GraphQL 服务器 当我们 查询 它时要检索什么。请记住,我们没有针对不同类型使用多个特定端点的 REST API。相反,我们定义了一个特殊的 Query
类型。
Query
类型
The Query
类型与其他任何 对象类型 一样定义:
type Query {# Fields go here}
这个类型的 字段 是我们架构中其他部分的 入口点。这些是我们的客户端可以 查询 的顶级 字段。
现在,我们只对获取主页的轨道列表感兴趣。让我们将该特定 查询 命名为 tracksForHome
以使其尽可能地描述性。我们希望这个 查询 返回一个非空列表,该列表包含非空的 Track
。我们还将添加一个不错的描述:
type Query {"Get tracks array for homepage grid"tracksForHome: [Track!]!}
我们的架构现在已完全定义,可以支持我们的第一个功能!以下是整个 schema.js
文件的外观:
const gql = require("graphql-tag");const typeDefs = gql`type Query {"Get tracks array for homepage grid"tracksForHome: [Track!]!}"A track is a group of Modules that teaches about a specific topic"type Track {id: ID!"The track's title"title: String!"The track's main author"author: Author!"The track's main illustration to display in track card or track page detail"thumbnail: String"The track's approximate length to complete, in minutes"length: Int"The number of modules this track contains"modulesCount: Int}"Author of a complete Track"type Author {id: ID!"Author's first and last name"name: String!"Author's profile picture url"photo: String}`;module.exports = typeDefs;
Query
类型的描述哪些始终为真?现在我们的基础模式已经准备好了,我们可以开始着手开发我们的GraphQL 服务器。
创建一个完整的模式,包含:一个类型 Query
,其中包含一个字段 spaceCats
用于获取 SpaceCat
的 List
。一个类型 SpaceCat
,包含其子字段:id
类型为 ID!
,name
类型为 String!
,age
类型为 Int
,missions
类型为 Mission
的 List
。最后定义 Mission
类型,包含其子字段:id
类型为 ID!
,name
类型为 String!
,description
类型为 String!
。
分享您关于本课的疑问和评论
您的反馈有助于我们改进!如果您遇到困难或感到困惑,请告知我们,我们会帮助您。所有评论都是公开的,必须遵守 Apollo 行为准则。请注意,已解决或已处理的评论可能会被删除。
您需要一个 GitHub 帐户才能在下面发布。没有帐户? 请改为在我们的 Odyssey 论坛上发布。