尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

用 Prisma 与 graphql-yoga 实现常见 Resolver 模式:从数据模型扩展、Schema 同步到自定义变更

用 Prisma 与 graphql-yoga 实现常见 Resolver 模式:从数据模型扩展、Schema 同步到自定义变更 后端数据库GraphQL【免费下载链接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]项目地址https://gitcode.com/gh_mirrors/pr/prisma1点击查看免费下载本篇技术指南以 Prisma 1.x 时代的typescript-basicGraphQL boilerplate 项目为背景系统讲解在graphql-yoga Prisma 架构中两个最常见的 Resolver 开发场景如何为数据模型新增字段并将其暴露到应用 API以及如何为 Mutation 添加自定义 Resolver。读完本文你将掌握数据模型 → Prisma 服务 → 应用 Schema → Resolver 委托这条完整的链路操作并理解ctx.db.mutation委托机制与exists权限校验模式的底层原理。前置背景两层 Schema 与 Resolver 委托在 Prisma graphql-yoga的典型架构中存在两个独立的 GraphQL Schema理解它们的区别是掌握 Resolver 模式的前提数据模型database/datamodel.graphql用 SDL 定义数据库结构是 Prisma 服务生成 CRUD API 的根基。Prisma 会基于它生成完整的Prisma Schema在typescript-basic项目中存放于src/generated/prisma.graphql包含对数据模型中每个类型生成的Query、Mutation、Subscription操作。应用 Schemasrc/schema.graphql定义你真正暴露给客户端应用的 GraphQL API其中的字段、参数和返回类型由你自行裁剪可以隐藏password之类的敏感字段也可以只暴露部分数据库字段。应用 Schema 的 Resolver 通常以委托方式实现——不直接写 SQL 或调用数据库驱动而是把查询/变更转发给底层 Prisma 服务。正如 prisma-binding 概述 所描述的prisma-binding为基于 Prisma 服务构建 GraphQL 服务器提供了一个便捷层通过把执行委托给底层 Prisma 服务的 API大多数 Resolver 可以写成一行代码。在typescript-basicboilerplate 的 入口文件 中Prisma实例被注入到 GraphQL 服务器的context中挂载为ctx.dbconst server new GraphQLServer({ typeDefs: ./src/schema.graphql, // points to the application schema resolvers, context: req ({ ...req, db: new Prisma({ endpoint: http://localhost:4466/my-app/dev, // the endpoint of the Prisma DB service secret: mysecret123, // specified in database/prisma.yml debug: true, // log all GraphQL queries mutations }), }), })因此在每个 Resolver 的四个标准参数(parent, args, ctx, info)中ctx.db就是通往 Prisma 服务的委托通道。场景一为数据模型新增字段并暴露到 API第一个常见场景是在数据库的User类型上新增一个address字段并希望客户端应用也能通过 GraphQL API 读写它。整个过程分三步。第 1 步修改数据模型打开database/datamodel.graphql在User类型中追加address字段注意 Prisma 的指令语法unique表示唯一约束!表示非空type User { id: ID! unique email: String! unique password: String! name: String! posts: [Post!]! address: String }这里address被定义为可空String表示并非每个用户都必须填写地址。数据模型是数据库真相的唯一来源Prisma 服务端所有表结构、索引和 CRUD 能力都由它派生。第 2 步部署更新后的数据模型在项目根目录执行prisma deploy这条命令会完成两件事部署新的数据库结构到本地服务Prisma 服务根据最新的datamodel.graphql更新底层数据库表结构在本地开发环境中即部署到通过prisma local start启动的 local cluster服务地址形如http://localhost:4466/my-app/dev下载数据库的最新 GraphQL Schema 到database/schema.graphql这个文件由 CLI 自动生成永远不要手工编辑任何结构变更都应通过修改datamodel.graphql并重新prisma deploy来完成。第 3 步把字段同步到应用 Schema仅仅修改数据模型还不够——数据模型中的字段默认不会自动出现在客户端 API 中。你需要在src/schema.graphql中把address字段也加到应用 Schema 的User类型上type User { id: ID! email: String! name: String! posts: [Post!]! address: String }注意这里应用 Schema 刻意没有password字段且id/email上没有unique指令——应用 Schema 最终决定了客户端能看到什么数据。数据模型负责数据库里有什么应用 Schema 负责API 对外暴露什么这是 Prisma 双 Schema 架构最核心的设计思想也是 权限教程 中role字段不暴露给客户端这一做法的理论基础。完成上述三步后重新启动服务器客户端即可在查询和变更中访问User.address。场景二添加一个自定义 Resolver删除 Post第二个场景是典型的应用层自定义操作为 API 添加一个delete变更用于删除一条Post记录。与数据库直连方案不同这里你不需要写任何数据库删除语句只需把参数转发给 Prisma 服务即可。第 1 步在应用 Schema 中声明 Mutation在src/schema.graphql的Mutation类型中加入delete字段type Mutation { createDraft(title: String!, text: String): Post publish(id: ID!): Post delete(id: ID!): Post }参数id: ID!用于定位要删除的Post返回类型为Post因此调用方可以在删除后拿到被删节点的字段。第 2 步实现 Resolver在src/index.js的Mutationresolvers 部分添加delete的实现delete(parent, { id }, ctx, info) { return ctx.db.mutation.deletePost( { where: { id } }, info ); }这段代码值得逐点拆解参数解构{ id }直接取出客户端传入的id委托调用ctx.db.mutation.deletePost是 Prisma 服务为数据模型中的Post自动生成的删除变更。它接收{ where: { id } }作为过滤条件透传info第二个参数info包含了客户端本次请求的完整 selection set即客户端要返回哪些字段Prisma 客户端会利用它构造精确的 GraphQL 文档只查询客户端真正需要的字段避免过度获取返回透传deletePost返回删除后的Post节点正好匹配应用 Schema 中声明的Post返回类型。从源码层面看这种deletePost({ where })的调用形态并不是手写约定而是由 Prisma 客户端实现 自动包装的客户端在buildMethods()中把 Prisma Schema 的Query、Mutation字段动态挂载到ctx.db上当字段名以delete开头时会自动把用户传入的参数包装为{ where: realArgs }见 Client.ts 中getTypes对delete前缀的处理对create前缀的字段则自动包装为{ data: realArgs }。这解释了为什么示例代码中传给deletePost的第一个参数只需要写{ id }而不是完整的{ where: { id } }——方便之余也意味着你需要对客户端参数会被自动包装这一行为有清晰认知。第 3 步启动服务器并验证运行yarn start或yarn dev以自动打开 GraphQL Playground启动服务器然后用下面的变更删除一条 Post把__POST_ID__替换为实际记录 idmutation { delete(id: __POST_ID__) { id } }yarn dev启动后Playground 会同时呈现两个 APIapp应用 Schema即src/schema.graphql定义的 API与databasePrisma CRUD API即生成的 Prisma Schema。你在app端发送delete变更数据最终由 Prisma 服务持久化也可以切换到database端直接发送deletePost(where: { id })来对照验证结果。纵深从委托到校验的 Resolver 演进掌握委托模式后一个自然的问题是如何在不破坏委托简洁性的前提下加入业务校验例如权限控制Prisma 生态给出的答案是在委托调用之前先用ctx.db.exists做数据访问检查。这与本文场景二属于同一 Resolver 编写范式只是多了一层前置判断async deletePost(parent, { id }, ctx, info) { const userId getUserId(ctx) const postExists await ctx.db.exists.Post({ id, author: { id: userId }, }) const requestingUserIsAdmin await ctx.db.exists.User({ id: userId, role: ADMIN, }) if (!postExists !requestingUserIsAdmin) { throw new Error(Post not found or you dont have access rights to delete it.) } return ctx.db.mutation.deletePost({ where: { id } }) }exists是 Prisma 客户端生成的内建函数它会对传入的where条件执行一次存在性查询并返回布尔值其实现可见 Client.ts 中的buildExists本质是调用对应模型的列表查询并判断结果是否非空。通过exists.Post({ id, author: { id: userId } })判断请求者是否为该 Post 的作者通过exists.User({ id: userId, role: ADMIN })判断请求者是否为管理员两者都失败才抛出权限错误否则继续委托。这样权限逻辑以可读的方式内联在 Resolver 中而底层数据操作仍然是一行委托调用完整示例可参考仓库中的 Permissions 教程。总结本文覆盖了graphql-yoga Prisma 开发中最常用的两类 Resolver 模式模式关键操作本质新增字段并暴露改datamodel.graphql→prisma deploy→ 同步src/schema.graphql数据模型与应用 Schema 的分层同步新增自定义 Resolver应用 Schema 声明字段 → 用ctx.db.mutation.xxx委托实现把数据库操作委托给 Prisma 生成的 CRUD API所有场景都建立在同一个核心心智模型上数据模型定义数据库真相应用 Schema 定义 API 边界Resolver 则是连接两者的薄委托层。在此基础上叠加exists校验即可把委托模式扩展为带权限控制的生产级 Resolver。相关项目结构与入口代码可继续参考 TypeScript Prisma Quickstart 与 prisma-binding 概述。赞分享后端数据库GraphQL【免费下载链接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]项目地址https://gitcode.com/gh_mirrors/pr/prisma1点击查看免费下载相关推荐Prisma graphql-yoga 常见 Resolver 模式实战数据模型扩展与自定义 Resolver 实现指南Prisma graphql yoga 常见 Resolver 模式实战数据模型扩展与自定义 Resolver 实现指南 本教程系统讲解在使用 graph后端数据库GraphQLPrisma 与 graphql-yoga 常见 Resolver 模式实战扩展数据模型与自定义变更解析器Prisma 与 graphql yoga 常见 Resolver 模式实战扩展数据模型与自定义变更解析器 本篇教程围绕 Prisma 官方 1.2 版本文档后端数据库GraphQLPrisma GraphQL Server 常见 Resolver 模式实战数据模型扩展与自定义 Mutationgraphql-yoga 篇Prisma GraphQL Server 常见 Resolver 模式实战数据模型扩展与自定义 Mutationgraphql yoga 篇 本教程后端数据库GraphQL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表