✏️让我们定义架构
在我们的 IDE 中打开最新检出的 Catstronauts 项目,让我们导航至server/src/
目录。在其中,我们将创建一个新的 schema.js
文件。
要开始使用我们的架构,首先我们需要几个软件包: apollo-server
和 graphql
。
-
graphql
软件包为解析和验证 GraphQL 查询提供了核心逻辑。 - 的 Apollo 服务器包提供与规范兼容的 GraphQL 服务器GraphQL服务器,它还提供了一些不错的实用工具,如
gql
字符串模版,我们稍后将用到。
从 server/
目录运行以下命令:
npm install apollo-server graphql
现在在 schema.js
中,我们从 apollo-server
中获取 gql
字符串模版:
const { gql } = require("apollo-server");
我们正在导入的这个 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}
该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
类型
该Query
类型定义类似于任何其他对象类型:
type Query {# Fields go here}
该类型的字段是进入我们架构其他部分的入口点。这些是我们的客户端可以
查询的顶级
字段。
现在,我们只针对主页获取曲目列表感兴趣。我们将具体查询 tracksForHome
命名得尽可能具有描述性。我们要让此 查询返回一个非空 Track
列表。我们还会添加一个好的说明:
type Query {"Get tracks array for homepage grid"tracksForHome: [Track!]!}
现在,我们的架构已完全明确,足以支持我们的首要功能!以下是整个架构的外观
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}
Query
类型的始终正确的?现在我们的基础架构已准备就绪,我们可以开始工作于 GraphQL 服务器。
创建包含以下内容的完整架构:类型 Query
,其中包含一个字段 spaceCats
,用于获取 List
的 SpaceCat
。类型 SpaceCat
,及其子字段:类型为 ID!
的 id
、类型为 String!
的 name
、类型为 Int
的 age
,以及类型为 List
的 Mission
的 missions
。最后定义 Mission
类型及其子字段:类型为 ID!
的 id
、类型为 String!
的 name
,以及类型为 String!
的 description
。
分享你关于此课程的问题和评论
您的反馈有助于我们改进网站!如果您遇到了障碍或困惑,欢迎您告知我们,我们会为您提供帮助。所有评论都是公开的,并且必须遵守 Apollo 行为准则。请注意,已经解决或处理的评论可能会被删除。
您需要一个 GitHub 帐户才能在此处发布。没有帐户? 改为在我们的 Odyssey 论坛中发帖。