2019年2月12日

将 GraphQL Nexus 与数据库一起使用

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

Using GraphQL Nexus with a Database

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

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

在上一篇文章中,我们介绍了 GraphQL Nexus,这是一个 GraphQL 库,可以为 TypeScript 和 JavaScript 实现代码优先开发。借助 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. 使用 Prisma 客户端在应用程序(例如 GraphQL API)中访问您的数据库

nexus-prisma 插件的幕后原理

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

  • 查询
    • user(...): User!:获取单个记录
    • users(...): [User!]!:获取记录列表
    • usersConnection(...): UserConnection!Relay 连接和聚合
  • 突变
    • 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

最后,继续添加一个启动脚本,您将在开发中使用它。它启动一个开发服务器,该服务器在后台监视您的文件,并在您编写代码时更新生成的 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 开始,该 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 添加一个始终返回完全大写标题的字段。以下是如何实现这一点:

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

Customize the GraphQL API via nexus-prisma

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

4.3) 隐藏 createPostupdatePost 突变

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

要隐藏 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 问题或在我们的 Slack 中联系我们来分享您的反馈。


非常感谢我们的开源工程师 Flavian Desvernenexus-prisma 插件上所做的出色工作 💪✨

不要错过下一篇文章!

注册 Prisma 新闻通讯