在本系列中,您将学习如何使用 React、GraphQL、Prisma 和其他一些有用的工具将这三者结合起来,实现端到端类型安全。
目录
- 简介
- 启动 GraphQL 服务器
- 设置模式构建器
- 定义
Date
标量类型 - 添加 Pothos Prisma 插件
- 创建 Prisma Client 的可重用实例
- 定义您的 GraphQL 类型
- 实现您的查询
- 应用 GraphQL 模式
- 总结和后续步骤
简介
在本节中,您将以前一篇文章中设置的项目为基础,扩展 GraphQL API 的功能。
在构建此 API 时,您将专注于确保与数据库的交互、解析器中的数据处理以及数据响应都是类型安全的,并且这些类型是同步的。
如果您错过了本系列的第一部分,以下是您将在此应用程序中使用的一些技术以及一些先决条件的快速概述。
您将使用的技术
以下是您将在本系列中使用的主要工具
- Prisma 作为对象关系映射器 (ORM)
- PostgreSQL 作为数据库
- Railway 用于托管您的数据库
- TypeScript 作为编程语言
- GraphQL Yoga 作为 GraphQL 服务器
- Pothos 作为代码优先的 GraphQL 模式构建器
- Vite 用于管理和搭建您的前端项目
- React 作为前端 JavaScript 库
- GraphQL Codegen 用于根据 GraphQL 模式为前端生成类型
- TailwindCSS 用于应用程序的样式设计
- Render 用于部署您的 API 和 React 应用程序
假定知识
虽然本系列将尝试从初学者的角度详细介绍所有内容,但以下知识将有所帮助
- JavaScript 或 TypeScript 的基本知识
- GraphQL 的基本知识
- React 的基本知识
开发环境
要跟随提供的示例进行操作,您需要具备
- Node.js 已安装。
- Prisma VSCode 扩展 已安装。(可选)
启动 GraphQL 服务器
构建 GraphQL API 所需的第一件事是运行中的 GraphQL 服务器。在本应用程序中,您将使用 GraphQL Yoga 作为您的 GraphQL 服务器。
安装 @graphql-yoga/node
和 graphql
包以开始使用
安装这些包后,您现在可以启动自己的 GraphQL 服务器。前往 src/index.ts
。将现有内容替换为此代码段
上面的代码执行以下操作
- 从 GraphQL Yoga 导入
createServer
函数 - 创建一个变量来保存 API 的端口,如果环境中不存在端口,则默认为
4000
- 创建 GraphQL 服务器的实例
- 在端口
4000
上启动服务器,并让控制台知道它正在运行
如果您启动服务器,您将可以访问正在运行的(空) GraphQL API
注意:GraphQL 服务器已启动并正在运行,但由于您尚未定义任何查询或 mutation,因此它尚不可用。
设置模式构建器
GraphQL 使用强类型模式来定义用户如何与 API 交互以及应返回哪些数据。构建 GraphQL 模式有两种不同的方法:代码优先和 SDL 优先。
- 代码优先:您的应用程序代码定义并生成 GraphQL 模式
- SDL 优先:您手动编写 GraphQL 模式
在本应用程序中,您将使用名为 Pothos 的流行模式构建器,采用代码优先方法。
要开始使用 Pothos,您首先需要安装核心包
接下来,创建 Pothos 模式构建器的实例作为可共享模块。在 src
文件夹中,创建一个名为 builder.ts
的新文件,用于保存此模块
现在,从 @pothos/core
包导入默认导出,并导出名为 builder
的实例
定义 Date
标量类型
默认情况下,GraphQL 仅支持有限的标量数据类型集
- Int
- Float
- String
- Boolean
- ID
但是,如果您回想一下您的 Prisma 模式,您会记得定义了一些字段,这些字段使用了 DateTime
数据类型。要在您的 GraphQL API 中处理这些类型,您需要定义自定义的 Date
标量类型。
幸运的是,由于开源社区的贡献,预制的自定义标量类型定义是可用的。您将使用的那个名为 graphql-scalars
您需要向模式构建器注册 Date
标量,以使其知道如何处理日期。模式构建器接受一个 泛型,您可以在其中指定各种配置。
进行以下更改以注册 Data
标量类型
以下是上面代码段中的更改。您
- 导入
Date
标量类型的解析器,该解析器处理在您的 API 中将值转换为正确的日期类型 - 使用
SchemaBuilder
的Scalars
配置注册了一个名为"Date"
的新标量类型,并配置了在访问和验证此类型的字段时要使用的 JavaScript 类型 - 通过提供导入的
DateResolver
,让构建器知道如何处理定义的Date
标量类型
现在,在您的 GraphQL 对象类型和解析器中,可以使用 Date
标量类型。
添加 Pothos Prisma 插件
接下来,您需要定义 GraphQL 对象类型。这些类型定义了您的 API 将通过查询公开的对象和字段。
Pothos 为 Prisma 提供了一个出色的插件,该插件使此过程更加顺畅,并在您的 GraphQL 类型和数据库模式之间提供类型安全。
注意:可以在不使用插件的情况下以类型安全的方式将 Pothos 与 Prisma 一起使用,但是该过程非常手动。有关详细信息,请参见此处。
首先,安装插件
此插件提供了一个 Prisma 生成器,用于生成 Pothos 所需的类型。将生成器添加到 prisma/schema.prisma
中的 Prisma 模式中
添加完成后,您将需要一种生成 Pothos 工件的方法。在本系列稍后部署此应用程序时,您将需要安装此 API 的 node 模块并重新生成 Prisma Client,因此请继续在 package.json
中创建一个新的 script
来处理此操作
现在,您可以运行该命令来安装您的 node 模块并重新生成 Prisma Client 和 Pothos 输出
当您运行上面的命令时,您应该看到 Prisma Client 和 Pothos 集成都已生成。
现在,这些类型已生成,请前往 src/builder.ts
。在这里,您将导入 PrismaPlugin
和生成的 Pothos 类型,并将它们应用于您的构建器
一旦添加生成的类型,您将注意到在 SchemaBuilder
的实例化中发生了 TypeScript 错误。
Pothos 非常智能,它知道,由于您正在使用 Prisma 插件,因此您需要向构建器提供 prisma
实例。Pothos 使用此实例来推断有关 Prisma Client 中类型的信息。在下一步中,您将创建该实例并将其添加到构建器中。
现在,在构建器实例中注册 Prisma 插件和生成的类型,以使 Pothos 了解它们
您将再次在此处看到 TypeScript 错误。这是因为 builder
现在期望将 Prisma Client 的实例提供给该函数。
在下一步中,您将实例化 Prisma Client 并在此处的 builder
中提供它。
创建 Prisma Client 的可重用实例
现在,您需要创建一个 Prisma Client 的可重用实例,该实例将用于查询您的数据库,并提供上一步中构建器所需的类型。
在 src
文件夹中创建一个名为 db.ts
的新文件
在该文件中,导入 Prisma Client 并创建名为 prisma
的客户端实例。导出该实例化的客户端
将 prisma
变量导入 src/builder.ts
并将其提供给 builder
以消除 TypeScript 错误
Pothos Prisma 插件现在已完全配置并可以使用了。这使用了 Prisma 生成的类型,并允许您在 GraphQL 对象类型和查询中轻松访问这些类型。
这样做的好处是,您现在拥有一个单一的事实来源(Prisma 模式),用于处理数据库中的类型、用于查询数据库的 API 以及 GraphQL 模式。
接下来,您将看到实际效果!
定义您的 GraphQL 类型
此时,您将使用配置了 Prisma 插件的构建器定义 GraphQL 对象类型。
注意:当您已经在 Prisma 模式中定义了数据形状时,手动定义 GraphQL 对象类型似乎是多余的。Prisma 模式定义了数据库中数据的形状,而 GraphQL 模式定义了 API 中可用的数据。
在 src
中创建一个名为 models
的新文件夹。然后在该新文件夹中创建一个 User.ts
文件
您将在此处定义 User
对象类型及其相关查询,这些查询将通过您的 GraphQL API 公开。导入 builder
实例
由于您正在使用 Pothos 的 Prisma 插件,因此 builder
实例现在有一个名为 prismaObject
的方法,您将使用该方法来定义您的对象类型。
该方法接受两个参数
name
:此新类型表示的 Prisma 模型的名称options
:要定义的类型的配置
使用该方法创建 "User"
类型
注意:如果您在键入
name
字段之前在空引号集中按 Ctrl + 空格键,您应该会获得一些不错的自动完成功能,其中包含来自 Prisma 模式的可用模型列表,这要归功于 Prisma 插件。
在 options
对象中,添加一个 fields
键,该键使用 Pothos 的 "expose" 函数定义 id
、name
和 messages
字段
注意:当您开始键入字段名称时,按 Ctrl + 空格键 将为您提供目标模型中与您正在使用的“expose”函数的数据类型匹配的字段列表。
上面的函数定义了一个 GraphQL 类型定义,并将其注册到 builder
实例中。从 builder
生成模式实际上不会在您的文件系统中存储您可以签出的 GraphQL 模式,但是您的 User
的结果类型定义将如下所示
接下来,在同一文件夹中添加另一个文件,名为 Message.ts
此文件将类似于 User.ts
文件,不同之处在于它将定义 Message
模型。
定义 id
、body
和 createdAt
字段。请注意,createdAt
字段在您的 Prisma 模式中具有 DateTime
类型,并且需要自定义配置来定义您定义的自定义 date
标量类型
此函数将生成以下 GraphQL 对象类型
实现您的查询
目前,您已经为您的 GraphQL 模式定义了对象类型,但是您尚未定义实际访问该数据的方式。为此,您首先需要初始化一个 Query
类型。
在您的 src/builder.ts
文件底部,使用 builder
的 queryType
函数初始化 Query
类型
这会注册一个特殊的 GraphQL 类型,该类型保存每个查询的定义,并充当 GraphQL API 的入口点。您在 builder.ts
文件中定义此类型,以确保查询构建器定义了 Query
类型,这样您就可以稍后向其添加查询字段。
在此 queryType
函数中,您可以直接添加查询定义,但是,您将在代码库中单独定义这些定义,以更好地组织您的代码。
将 prisma
实例导入 src/models/User.ts
然后,使用 builder
的 queryField
函数,定义一个 "users"
查询,该查询公开您定义的 User
对象类型
上面的代码段
- 向 GraphQL 模式的
Query
类型添加一个名为"users"
的字段 - 定义一个字段,该字段解析为 Prisma 模式中的某种类型
- 让 Pothos 知道此字段将解析为 Prisma Client 的
User
类型的数组 - 为此字段设置解析器函数。
注意:
resolve
函数的query
参数位于参数列表的开头。这是 Pothos 在使用prismaField
函数时填充的特定字段,用于以高性能的方式加载数据和关系。如果您来自 GraphQL 背景,这可能会令人困惑,因为它更改了参数的预期顺序。
为了更好地可视化所发生的事情,以下是 Query
类型和 users
查询,它们将由本节中的代码生成
应用 GraphQL 模式
现在,您已经定义并实现了所有 GraphQL 对象类型和查询。最后需要的是一种在单个位置注册所有这些类型并基于您的配置生成 GraphQL 模式的方法。
在 src
中创建一个名为 schema.ts
的新文件
此文件将仅导入模型,从而导致运行文件中的代码,并运行 builder
实例的 toSchema
函数以生成 GraphQL 模式
toSchema
函数生成 GraphQL 模式的抽象语法树 (AST) 表示形式。在下面,您可以看到 AST 和 GraphQL 表示形式的外观
在您的 src/index.ts
文件中,导入您刚刚创建的 schema
变量。createServer
函数的配置对象采用名为 schema
的键,该键将接受生成的 GraphQL 模式
太棒了!您的 GraphQL 模式已使用代码优先方法定义,您的 GraphQL 对象和查询类型与您的 Prisma 模式模型同步,并且您的 GraphQL 服务器正在接收生成的 GraphQL 模式。
此时,运行服务器,以便您可以试用 API
运行上述命令后,在浏览器中打开 https://127.0.0.1:4000/graphql 以访问 GraphQL playground。您应该看到一个看起来像这样的页面
在屏幕的左上角,点击Explorer按钮以查看 API 的可用查询和 mutation
如果您单击users查询类型,则屏幕右侧将自动填充用户数据的查询。
点击“执行查询”按钮运行该查询以查看 API 的实际效果
随意试用不同的选项,以选择您要查询的字段以及您要包含的“messages”关系中的哪些数据。
总结和后续步骤
在本文中,您构建了整个 GraphQL API。API 的构建方式是类型安全的,它利用了 Prisma 生成的类型。这些类型与 Pothos Prisma 插件一起,使您能够确保 ORM、GraphQL 对象类型、GraphQL 查询类型和解析器中的类型都与数据库模式同步。
在此过程中,您
- 使用 GraphQL Yoga 设置了 GraphQL 服务器
- 设置了 Pothos 模式构建器
- 定义了您的 GraphQL 对象和查询类型
- 使用 Prisma Client 查询了数据
在下一篇文章中,您将通过设置代码生成来保持前端客户端和 API 上的类型同步来完成收尾工作。然后,您将部署您完成的应用程序!
不要错过下一篇文章!
注册 Prisma 新闻通讯