2019年2月12日

将 GraphQL Nexus 与数据库一起使用

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

Using GraphQL Nexus with a Database

⚠️ 本文已过时,因为它与现已 已废弃Prisma 1 相关。要了解最新版本的 Prisma,请阅读文档。 ⚠️

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

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

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

nexus-prisma 支持 PostgreSQL、MySQL 和 MongoDB。在此查找其文档


TLDR:nexus-prisma 插件的优势

  • 为您的 Prisma 模型提供 GraphQL CRUD 操作
  • 自定义您的 Prisma 模型,例如 隐藏特定字段 或 添加计算字段
  • 完全类型安全:为 GraphQL schema 和数据库提供一致的类型集
  • 与 GraphQL 生态系统兼容(例如 apollo-servergraphql-yoga 、...)

理解 nexus-prisma 工作流程

Prisma client 作为 ORM 替代品

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

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

nexus-prisma 插件底层原理

当加入 nexus-prisma 时,还需要一步:调用 nexus-prisma-generate codegen CLI。它会为您的 Prisma 模型生成完整的 GraphQL CRUD API 构建块,例如 对于 User 模型,它包含

  • 查询
    • 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 client
  3. 通过 nexus-prisma 公开完整的 CRUD GraphQL API
  4. 通过 nexus-prisma 定制 GraphQL API

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

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

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

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

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

  1. 选择 Demo server(包含 Prisma Cloud 中的免费托管演示数据库)
  2. 在浏览器中通过 Prisma Cloud 进行认证(如果需要)
  3. 回到您的终端,确认所有建议的值

作为 Demo server 的替代方案,您也可以使用 Docker 在本地运行 Prisma

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

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

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

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

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

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

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

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

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

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

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

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

在这个简短的教程中,我们不太关注文件结构。请查看我们的 graphql-auth 示例,了解适当的设置和模块化的 schema。

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

示例查询

示例变更

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

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 不能自动解析),我们还需要为其附加一个 resolver。

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)

请务必从 nexus 包中导入 stringArgidArg 以使其工作。

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


我们的代码优先 GraphQL 文章的 3 个关键要点

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

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

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

以下是本系列的主要要点

  1. 代码优先方法让您能够以语言习惯的方式构建 GraphQL 服务,无需额外的工具(“您唯一需要的工具是您的编程语言”),同时保留了 SDL 作为沟通工具的优势。
  2. GraphQL Nexus 让开发者能够使用灵活且类型安全的 API 构建他们的 schema。开发者通过自动补全和构建时错误检查获得惊人的体验。
  3. nexus-prisma 插件构建在 Prisma 模型之上,通过公开和定制自动生成的 CRUD 构建块,让开发者能够构建 GraphQL API。

今天就来试试 nexus-prisma 吧 🙌

您可以通过几种方式试用 nexus-prisma。您可以按照文档中的 入门指南 部分,或探索我们的 TypeScript GraphQL 示例

请通过提交 GitHub Issue 或在我们的 Slack 中分享您的反馈。


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

不要错过下一篇文章!

订阅 Prisma 新闻通讯