4. 构建我们的架构
10m

✏️ 让我们定义该架构

打开我们的 IDE 并检出 Catstronauts 项目,然后导航到server/src/目录。在该目录中,我们将创建一个新的schema.js文件。

为了开始构建我们的架构,我们首先需要几个包: @apollo/servergraphql 以及 graphql-tag

  • The @apollo/server 包提供了一个完整的、符合规范的
  • The graphql 包提供了解析和验证 查询的核心逻辑。
  • The graphql-tag 包提供了 gql 模板字面量,我们将在稍后使用它。

server/ 目录运行以下命令:

npm install @apollo/server graphql graphql-tag

现在在 schema.js 中,让我们从 graphql-tag 获取 gql 模板字面量:

const gql = require("graphql-tag");

我们导入的这个 gql 是什么?它是一个带标签的模板字面量,用于包装 字符串,例如我们即将编写的架构定义。

这会将 字符串转换为 Apollo 库在处理 和架构时所期望的格式,并且它还支持语法高亮显示。

接下来,让我们声明一个 typeDefs(代表“类型定义”)常量,并为其分配 gql 模板,我们的定义将存储在该模板中。同时,我们现在将导出 typeDefs,因为我们稍后会在服务器文件中使用它。

const typeDefs = gql`
# Schema definitions go here
`;
module.exports = typeDefs;

请注意,我们使用反引号(`)与 gql 标签一起使用,不要与单引号(')混淆。

很好,我们已经准备好定义我们的类型了。参考我们的模型,我们确定每个学习轨道的以下数据是必要的

  • 标题
  • 缩略图
  • 时长
  • 模块数量
  • 作者姓名
  • 作者照片

我们如何将这些数据组织成类型?

我们可以创建一个名为 Track 的单个类型,将所有这些 放入其中,然后结束。但从业务领域的角度来看,这样合理吗?不尽然。首先,一个作者可能会创建多个轨道,并且该作者的信息会在多个位置进行不必要的重复。相反,我们需要从独立实体的角度考虑。我们将从两个实体开始: TrackAuthor

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: String
length: Int
modulesCount: 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
}

太好了,我们的第一个功能现在已完全体现在我们的架构中。这些是我们能够检索的数据类型。

不过,我们还缺少一个部分:如何告诉 当我们 它时要检索什么。请记住,我们没有针对不同类型使用多个特定端点的 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 文件的外观:

server/src/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 类型的描述哪些始终为真?

现在我们的基础模式已经准备好了,我们可以开始着手开发我们的

代码挑战!

创建一个完整的模式,包含:一个类型 Query,其中包含一个字段 spaceCats 用于获取 SpaceCatList。一个类型 SpaceCat,包含其子字段:id 类型为 ID!name 类型为 String!age 类型为 Intmissions 类型为 MissionList。最后定义 Mission 类型,包含其子字段:id 类型为 ID!name 类型为 String!description 类型为 String!

正在加载...
加载进度
上一页

分享您关于本课的疑问和评论

您的反馈有助于我们改进!如果您遇到困难或感到困惑,请告知我们,我们会帮助您。所有评论都是公开的,必须遵守 Apollo 行为准则。请注意,已解决或已处理的评论可能会被删除。

您需要一个 GitHub 帐户才能在下面发布。没有帐户? 请改为在我们的 Odyssey 论坛上发布。