February 12, 2019

将 GraphQL Nexus 与数据库结合使用

GraphQL Nexus 是一个代码优先、类型安全的 JavaScript/TypeScript GraphQL 模式构建库。了解如何使用 Prisma 客户端和新的 nexus-prisma 插件将其连接到数据库。

Using GraphQL Nexus with a Database

⚠️ 本文已过时,因为它与 Prisma 1 相关,该版本现已 弃用。要了解有关最新版 Prisma 的更多信息,请阅读文档。⚠️

回顾:使用 GraphQL Nexus 进行代码优先开发

在上一篇文章中,我们介绍了 GraphQL Nexus,这是一个支持 TypeScript 和 JavaScript 代码优先开发的 GraphQL 库。使用 Nexus,GraphQL 模式是以编程方式定义和实现的。因此,它遵循其他语言中 GraphQL 服务器的成熟方法,例如 sangria-graphql (Scala)、graphlq-rubygraphene (Python)。

今天的文章是关于将基于 Nexus 的 GraphQL 服务器连接到数据库,使用 Prisma 客户端以及新的 nexus-prisma 插件。我们稍后将通过一个从头开始构建博客应用程序的 GraphQL API 的实际示例来指导您。

nexus-prisma 适用于 PostgreSQL、MySQL 和 MongoDB。此处提供其文档


TLDR:nexus-prisma 插件的优势

  • 对 GraphQL 中的 Prisma 模型进行 CRUD 操作
  • 自定义您的 Prisma 模型,例如隐藏某些字段添加计算字段
  • 完全类型安全:GraphQL 模式和数据库的类型集合一致
  • 与 GraphQL 生态系统兼容(例如 apollo-servergraphql-yoga 等)

了解 nexus-prisma 工作流

Prisma 客户端作为 ORM 替代方案

如果您之前没有使用过 Prisma,这里快速概述一下它的工作原理

  1. 定义您的数据模型或让 Prisma 内省您现有的数据库
  2. 生成您的 Prisma 客户端,即一个类型安全的数据库客户端
  3. 在应用程序(例如 GraphQL API)中使用 Prisma 客户端访问数据库

nexus-prisma 插件内部原理

当加入 nexus-prisma 时,还有另一个步骤:调用 nexus-prisma-generate 代码生成 CLI。它为您的 Prisma 模型生成完整的 GraphQL CRUD API 的构建块,例如对于 User 模型,它包括

  • 查询 (Queries)
    • user(...): User!:获取单个记录
    • users(...): [User!]!:获取记录列表
    • usersConnection(...): UserConnection!Relay 连接和聚合
  • 变更 (Mutations)
    • createUser(...): User!:创建新记录
    • updateUser(...): User:更新记录
    • deleteUser(...): User:删除记录
    • updatesManyUsers(...): BatchPayload!:批量更新多条记录
    • deleteManyUsers(...): BatchPayload!:批量删除多条记录
  • GraphQL 输入类型
    • UserCreateInput:封装记录的所有字段
    • UserUpdateInput:封装记录的所有字段
    • UserWhereInput:提供记录所有字段的过滤器
    • UserWhereUniqueInput:提供记录唯一字段的过滤器
    • UserUpdateManyMutationInput:封装可批量更新的字段
    • UserOrderByInput:按字段指定升序或降序

UserCreateInputUserUpdateInput 在处理关系字段的方式上有所不同。

使用 nexusnexus-prisma 编写 GraphQL 服务器代码时,您可以通过公开和自定义这些操作来满足您自己的 API 需求

Writing GraphQL server code with nexus and nexus-prisma

生成 CRUD 构建块后,您可以使用 nexus-prisma 中的 prismaObjectType 开始公开(和自定义)它们。以下代码片段描述了一个实现,它基于 Prisma 和 nexus-prisma 为 TODO 列表应用程序提供 GraphQL API

我们将 prismaObjectType 应用于 QueryMutation。对于 Query,我们保留所有字段(即 todotodoestodoesConnection)。对于 Mutation,我们使用 prismaFields 来自定义公开的操作。

prismaFields 允许我们选择要公开的操作。在这种情况下,我们只想保留创建模型的操作(createTodo)。从生成的 CRUD 构建块中,我们不包含 updateTodo 也不包含 deleteTodo,而是实现我们自己的 markAsDone(id: ID!) 变更,用于标记某个 Todo 已完成。


示例:从标准 CRUD 到自定义 GraphQL API

现在,让我们快速了解一个标准的 Prisma 用例,看看如何通过几个简单的步骤快速为博客应用程序构建 GraphQL API。我们将做以下工作:

  1. 使用 TypeScript 设置 Prisma 项目(使用免费的演示数据库)
  2. 定义模型,迁移数据库并生成 Prisma 客户端
  3. 通过 nexus-prisma 公开完整的 CRUD GraphQL API
  4. 通过 nexus-prisma 自定义 GraphQL API

如果您想跟着做,需要安装 Prisma CLI

1) 使用 TypeScript、nexusnexus-prisma 设置 Prisma 项目

本节主要介绍您的项目设置。如果您不想跟着编写代码,可以跳过本节,否则请展开下面的部分。

使用 Prisma CLI 创建一个简单的 Prisma 项目

在交互式提示中,选择以下选项

  1. 选择 演示服务器(包括 Prisma Cloud 中的免费托管演示数据库)
  2. 在浏览器中使用 Prisma Cloud 进行身份验证(如果需要)
  3. 回到您的终端,确认所有建议的值

作为演示服务器的替代方案,您也可以使用 Docker 在本地运行 Prisma

接下来,您需要配置 nexus-prisma 工作流。添加以下依赖项(在 myblog 目录中)

接下来,将以下两行添加到 prisma.yml 的末尾

这确保了无论何时您对模型进行更改,Prisma 客户端以及生成的 nexus-prisma CRUD 构建块都会自动更新。

由于我们使用的是 TypeScript,让我们快速添加一个 tsconfig.json

最后,继续添加一个 start 脚本,您将用它进行开发。它会启动一个开发服务器,在后台监视您的文件并在您编写代码时更新生成的 SDL 和 Nexus 类型定义。将其添加到您的 package.json

2) 定义模型、迁移数据库并生成 Prisma 客户端

prisma init 命令在 datamodel.prisma 中创建了一个默认的 User 模型。由于我们正在构建一个博客应用程序,让我们将模型调整为我们的应用程序域:

接下来,您需要通过将数据模型应用到数据库来迁移数据库。使用以下命令,在 datamodel.prisma 中定义的每个模型都将映射到底层数据库中的一个表:

由于您之前在 prisma.yml 中配置了 post-deploy 钩子,您的 Prisma 客户端和 CRUD 构建块会自动更新。

3) 通过 nexus-prisma 公开完整的 CRUD GraphQL API

在项目的早期阶段,API 公开完整的 CRUD 功能通常很有帮助——更受约束的 API 需求通常会随着时间的推移而出现。nexus-prisma 通过提供从完整 CRUD 到自定义 API 操作的直接路径,完美地考虑了这一点。

让我们从一个 GraphQL API 开始,它为已定义模型公开完整的 CRUD(请注意,这包括过滤器、分页和排序)。创建一个名为 index.ts 的新文件,并向其中添加以下代码:

在这个简短的教程中,我们不太关注文件结构。有关正确的设置和模块化模式,请查看我们的 graphql-auth 示例。

运行 npm run start 后,您可以在 http://localhost:4000 上打开您的 GraphQL 服务器的 GraphQL Playground。通过您上面编写的少量代码,您就已经拥有了一个功能齐全的 GraphQL CRUD API。

示例查询

示例变更

这是如何工作的?nexus-prisma-generate 生成了一个 GraphQL 模式,它为 Prisma 模型(您的 CRUD 构建块)提供了 CRUD API。这个 GraphQL 模式遵循 OpenCRUD 规范。使用 prismaObjectType 函数,您现在可以公开和自定义该模式的操作。

prismaObjectTypeprismaFields 使用白名单方法,这意味着您需要明确列出要公开的字段。通配符运算符 * 包含所有字段。

Expose full CRUD GraphQL API via nexus-prisma

4) 通过 nexus-prisma 自定义 GraphQL API

在本节中,我们将学习如何自定义 nexus-prisma 的 CRUD GraphQL API。具体来说,我们将:

  1. User 模型中隐藏一个字段
  2. Post 模型添加一个计算字段
  3. 隐藏 createPostupdatePost 变更
  4. 添加两个自定义的 createDraftpublish 变更

4.1) 从 User 模型中隐藏一个字段

在本节中,我们将从 User 模型中隐藏 email 字段。

要自定义模型,我们需要对其应用 prismaObjectType 函数,并将 definition(t) 函数作为选项传入

通过在模型 t 上调用 prismaFields,我们可以自定义公开的字段(及其参数)。由于 email 未包含在列表中,因此它将从我们的 GraphQL API 中移除。

Hide a field from the User model

要应用这些更改,您需要显式地将 User 传递到 makePrismaSchema 内部的 types 数组中

请注意,您的编辑器能够根据生成的 CRUD 构建块建议要传递给 prismaObjectTypeprismaFields 的内容。这意味着当您键入 prismaObjectType('') 并按下 ctrl+space 时,它会建议所有生成的 CRUD 构建块的名称。当调用 t.prismaFields(['']) 时,它会建议 t 的字段。

4.2) 向 Post 模型添加一个计算字段

使用 nexus-prisma 的新代码优先方法也使得向 Prisma 模型添加计算字段变得容易。假设您想向 Post 添加一个始终返回完全大写的 title 的字段。以下是实现方法:

我们使用来自 graphql-nexust.string(...) API 向我们的模型添加一个新字段。因为它是一个计算字段(因此不能被 nexus-prisma 自动解析),我们还需要为其附加一个解析器。

Customize the GraphQL API via nexus-prisma

和以前一样,您需要显式地将自定义的 Post 模型添加到 types 数组中

4.3) 隐藏 createPostupdatePost 变更

与我们从 User 模型中隐藏 email 字段的方式相同,我们也可以从作为生成的 nexus-prisma CRUD 构建块一部分的 Query/Mutation 类型中隐藏操作。

要隐藏 createPostupdatePost,我们再次需要将 definition(t) 作为选项传递给 prismaObjectType。请注意,一旦我们在类型上调用 prismaFields,我们就需要明确列出所有我们想要保留的字段(空数组将被解释为“不保留任何操作”)

生成的 CRUD GraphQL API 还包括批量和 upsert 操作,为了简洁起见,我们在这里也将其排除。

4. 添加两个自定义的 createDraftpublish 变更

最后,我们向 GraphQL API 添加两个自定义变更。它们的 SDL 定义应如下所示:

要实现这些变更,您需要向 Mutation 类型添加两个字段(通过调用 nexus API 中的 t.field( ... )

请务必从 nexus 包中导入 stringArgidArg 才能使其正常工作。

GraphQL Nexus 还会生成 GraphQL 模式的 SDL 版本,您可以在 ./generated/schema.graphql 中找到它。我们 GraphQL API 的最终版本如下所示:


从我们的代码优先 GraphQL 文章中得到的 3 个关键启示

这是我们关于代码优先 GraphQL 服务器系列文章的最后一部分。

GraphQL Nexusnexus-prisma 插件实现了我们两年多来积极为 GraphQL 生态系统贡献所积累的经验。在发现 SDL 优先方法存在太多问题后,我们对当前涌现的新代码优先工具感到无比兴奋。

我们坚信 GraphQL Nexus(以及其他代码优先方法,例如 TypeGraphQL)将彻底改变未来 GraphQL 模式的构建方式。

以下是本系列文章的主要启示:

  1. 代码优先方法允许您以语言惯用的方式构建 GraphQL 服务器,而无需额外的工具(“您唯一需要的工具是您的编程语言”),同时保留了 SDL 作为通信工具的优势。
  2. GraphQL Nexus 使开发人员能够使用灵活且类型安全的 API 构建其模式。通过自动完成和构建时错误检查,开发人员获得了出色的体验。
  3. nexus-prisma 插件构建于 Prisma 模型之上,允许开发人员通过公开和自定义自动生成的 CRUD 构建块来构建 GraphQL API。

立即试用 nexus-prisma 🙌

有几种方法可以试用 nexus-prisma。您可以遵循文档中的入门部分,或者探索我们的TypeScript GraphQL 示例

请通过提交 GitHub issue 或在我们的 Slack 中联系我们来分享您的反馈。


向我们的开源工程师 Flavian Desverne 致以崇高的敬意,感谢他在 nexus-prisma 插件方面做出的杰出贡献 💪✨

不要错过下一篇文章!

订阅 Prisma 新闻通讯

© . All rights reserved.