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

回顾:使用 GraphQL Nexus 进行代码优先开发
在上一篇文章中,我们介绍了 GraphQL Nexus,一个为 TypeScript 和 JavaScript 启用代码优先开发的 GraphQL 库。使用 Nexus,GraphQL 模式是编程定义和实现的。因此,它遵循其他语言中 GraphQL 服务器的成熟方法,例如 sangria-graphql (Scala)、graphlq-ruby 或 graphene (Python)。
今天的文章是关于将您基于 Nexus 的 GraphQL 服务器连接到数据库,使用 Prisma 客户端以及新的 nexus-prisma 插件。我们稍后将通过一个从零开始构建博客应用 GraphQL API 的实际示例来指导您。
nexus-prisma支持 PostgreSQL、MySQL 和 MongoDB。有关文档,请点击此处。
TLDR:nexus-prisma 插件的优势
- 为您的 Prisma 模型在 GraphQL 中执行 CRUD 操作
- 自定义您的 Prisma 模型,例如隐藏某些字段或添加计算字段
- 完全类型安全:为 GraphQL 模式和数据库提供一致的类型集
- 与 GraphQL 生态系统兼容(例如
apollo-server、graphql-yoga等)
理解 nexus-prisma 工作流
Prisma 客户端作为 ORM 替代品
如果您以前没有使用过 Prisma,这里简要介绍一下它的工作原理
- 定义您的数据模型或让 Prisma 内省您现有的数据库
- 生成您的 Prisma 客户端,即一个类型安全的数据库客户端
- 在应用程序(例如 GraphQL API)中使用 Prisma 客户端访问您的数据库
nexus-prisma 插件的幕后
当将 nexus-prisma 添加到组合中时,还有另一个步骤:调用 nexus-prisma-generate codegen 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:按字段指定升序或降序
UserCreateInput和UserUpdateInput在处理关系字段的方式上有所不同。
在使用 nexus 和 nexus-prisma 编写 GraphQL 服务器代码时,您可以通过公开和自定义这些操作来满足您自己的 API 需求
生成 CRUD 构建块后,您可以使用 nexus-prisma 中的 prismaObjectType 开始公开(和自定义)它们。以下代码片段描述了一个基于 Prisma 和 nexus-prisma 为待办事项列表应用程序提供 GraphQL API 的实现
我们将 prismaObjectType 应用于 Query 和 Mutation。对于 Query,我们保留所有字段(即 todo、todoes 和 todoesConnection)。对于 Mutation,我们使用 prismaFields 来自定义公开的操作。
prismaFields 允许我们选择要公开的操作。在这种情况下,我们只想保留创建模型的操作(createTodo)。从生成的 CRUD 构建块中,我们既不包括 updateTodo 也不包括 deleteTodo,而是实现我们自己的 markAsDone(id: ID!) 突变来勾选某个 Todo。
示例:从标准 CRUD 到自定义 GraphQL API
现在,让我们快速了解一个标准的 Prisma 用例,看看如何通过几个简单的步骤快速为博客应用程序构建 GraphQL API。我们将做以下工作
- 使用 TypeScript 设置 Prisma 项目(使用免费演示数据库)
- 定义模型、迁移数据库并生成 Prisma 客户端
- 通过
nexus-prisma公开完整的 CRUD GraphQL API - 通过
nexus-prisma自定义 GraphQL API
如果您想跟着做,您需要安装 Prisma CLI
1) 使用 TypeScript、nexus 和 nexus-prisma 设置 Prisma 项目
本节主要涉及您的项目设置。如果您不想编码,请随意跳过此部分,否则请展开以下部分。
使用 Prisma CLI 创建一个简单的 Prisma 项目
在交互式提示中,选择以下选项
- 选择 演示服务器(包括 Prisma Cloud 中免费托管的演示数据库)
- 在浏览器中通过 Prisma Cloud 认证(如果需要)
- 回到终端,确认所有建议值
除了演示服务器,您还可以使用 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 操作的直接路径,完美地考虑了这一点。
让我们从一个公开定义模型的完整 CRUD 的 GraphQL API 开始(请注意,这包括过滤器、分页和排序)。创建一个名为 index.ts 的新文件,并向其中添加以下代码
在这个简短的教程中,我们不太关注文件结构。有关正确的设置和模块化模式,请查看我们的
graphql-auth示例。
运行 npm run start 后,您可以在 https://:4000 上打开您的 GraphQL 服务器的 GraphQL Playground。使用您上面编写的少量代码,您已经拥有了一个成熟的 GraphQL CRUD API。
这是如何工作的?nexus-prisma-generate 生成了一个 GraphQL 模式,该模式为 Prisma 模型(您的 CRUD 构建块)提供了一个 CRUD API。此 GraphQL 模式遵循 OpenCRUD 规范。使用 prismaObjectType 函数,您现在可以公开和自定义该模式的操作。
prismaObjectType 和 prismaFields 使用白名单方法,这意味着您需要明确列出要公开的字段。通配符运算符 * 包括所有字段。
4) 通过 nexus-prisma 自定义 GraphQL API
在本节中,我们将学习如何自定义 nexus-prisma 的 CRUD GraphQL API。具体来说,我们将
- 从
User模型中隐藏一个字段 - 为
Post模型添加一个计算字段 - 隐藏
createPost和updatePost突变 - 添加两个自定义的
createDraft和publish突变
4.1) 从 User 模型中隐藏一个字段
在本节中,我们将从 User 模型中隐藏 email 字段。
要自定义模型,我们需要将 prismaObjectType 函数应用于它,并将 definition(t) 函数作为选项传递
通过在模型 t 上调用 prismaFields,我们可以自定义公开的字段(及其参数)。因为 email 不包含在列表中,所以它将从我们的 GraphQL API 中删除。
要应用更改,您需要显式地将 User 传递给 makePrismaSchema 内部的 types 数组
请注意,您的编辑器能够根据生成的 CRUD 构建块建议要传递给 prismaObjectType 和 prismaFields 的内容。这意味着当您键入 prismaObjectType('') 并按下 ctrl+space 时,它会建议所有生成的 CRUD 构建块的名称。当调用 t.prismaFields(['']) 时,它会建议 t 的字段
4.2) 为 Post 模型添加一个计算字段
使用 nexus-prisma 的新代码优先方法也使得为 Prisma 模型添加计算字段变得容易。假设您想为 Post 添加一个字段,该字段始终返回完全大写的 title。下面是如何实现它
我们使用来自 graphql-nexus 的 t.string(...) API 为我们的模型添加一个新字段。因为它是计算字段(因此不能由 nexus-prisma 自动解析),我们还需要为其附加一个解析器。
如前所述,您需要将自定义的 Post 模型显式添加到 types 数组中
4.3) 隐藏 createPost 和 updatePost 突变
与我们从 User 模型中隐藏 email 字段的方式相同,我们也可以从作为生成的 nexus-prisma CRUD 构建块一部分的 Query/Mutation 类型中隐藏操作。
要隐藏 createPost 和 updatePost,我们再次需要将 definition(t) 作为选项传递给 prismaObjectType。请注意,一旦我们在类型上调用 prismaFields,我们需要显式列出所有要保留的字段(空数组将被解释为“不保留任何操作”)
生成的 CRUD GraphQL API 还包括批量和 upsert 操作,为了简洁起见,我们在此也将其排除。
4. 添加两个自定义的 createDraft 和 publish 突变
最后,我们向 GraphQL API 添加了两个自定义突变。它们应该看起来像这样的 SDL 定义
要实现这些突变,您需要向 Mutation 类型添加两个字段(通过调用来自 nexus API 的 t.field( ... ))
请务必从 nexus 包中导入 stringArg 和 idArg,以使其正常工作。
GraphQL Nexus 还生成 GraphQL 模式的 SDL 版本,您可以在 ./generated/schema.graphql 中找到它。我们的 GraphQL API 的最终版本如下所示
我们代码优先 GraphQL 文章的 3 个主要收获
这是我们关于代码优先 GraphQL 服务器开发系列文章的最后一部分。
GraphQL Nexus 和 nexus-prisma 插件实现了我们作为 GraphQL 生态系统的积极贡献者两年多来所收集到的经验教训。在发现 SDL 优先方法存在太多问题之后,我们对目前正在涌现的新代码优先工具感到非常兴奋。
我们坚信 GraphQL Nexus(以及其他代码优先方法,如 TypeGraphQL)将极大地改变未来 GraphQL 模式的构建方式。
以下是本系列的主要收获
- 代码优先方法允许您以语言惯用的方式构建 GraphQL 服务器,而无需额外的工具(“您唯一需要的工具是您的编程语言”),同时保留 SDL 作为通信工具的优势。
- GraphQL Nexus 允许开发人员使用灵活且类型安全的 API 构建其模式。由于自动完成和构建时错误检查,开发人员获得了出色的体验。
nexus-prisma插件基于 Prisma 模型构建,并允许开发人员通过公开和自定义自动生成的 CRUD 构建块来构建 GraphQL API。
立即试用 nexus-prisma 🙌
您可以通过多种方式试用 nexus-prisma。您可以遵循文档中的入门部分,或者探索我们的TypeScript GraphQL 示例。
请通过提出 GitHub issue 或在我们的Slack 中联系我们来分享您的反馈。
衷心感谢我们的开源工程师 Flavian Desverne 在 nexus-prisma 插件方面所做的出色工作 💪✨
不要错过下一篇文章!
订阅 Prisma 新闻通讯