后端数据库GraphQL【免费下载链接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]项目地址https://gitcode.com/gh_mirrors/pr/prisma1点击查看免费下载在 Graphcool Framework 中业务逻辑可以通过 Hooks数据校验/转换、Resolver Functions自定义解析器与 Server-side Subscriptions服务端订阅三类 serverless 函数挂载到 GraphQL API 上。迁移到 Prisma 后这些函数的能力并没有消失而是改变了两点一方面Hooks 与 Resolver Functions 的实现位置从平台托管下沉到了应用层你自己的 GraphQL Server resolver另一方面服务端订阅的触发方式统一收敛为Webhook指向你自行部署的 HTTP 端点。本文以 04-Functions.md 为主线逐一给出三类功能的迁移前后对照示例并结合本仓库中 prisma.yml 订阅配置说明、服务端订阅参考文档 以及 CLI 解析源码 PrismaDefinition.ts 做纵深佐证。读完本文你将能熟练地把 Graphcool 项目中的函数逻辑迁移到 Prisma 的 resolver 与 webhook 模型中并正确书写prisma.yml的subscriptions配置。迁移总览三类函数分别去向何处Graphcool Framework 的函数体系包含三类能力它们的职责边界在迁移前后对比如下Graphcool 函数类型用途迁移后的落点Hooks对 mutation 做同步的数据校验与转换应用层 GraphQL resolver 内部先处理再调 Prisma 客户端Resolver Functions扩展自动生成的 CRUD API如认证、包装 REST API应用层 GraphQL resolverschema 扩展 普通 JS 函数实现Server-side Subscriptions订阅数据变更事件并触发处理逻辑由 Prisma 通过 Webhook 推送事件到自部署的 HTTP 端点其背后的核心思想是Prisma 专注于数据层的 GraphQL API不再托管业务函数所有与业务规则相关的同步逻辑都应在你的应用服务器中执行Prisma 仅负责通过其生成的客户端暴露数据操作能力。整个迁移系列的其他主题数据建模、认证鉴权、文件处理、服务器托管可参见 Graphcool 迁移指南目录。为便于说明本文假设的数据模型datamodel如下type User { id: ID! unique name: String! }并假设你的 GraphQL 服务器对外暴露如下应用 schemaapplication schematype Query { users: [User!]! } type Mutation { createUser(name: String!): User! }Hooks 的迁移业务规则下沉到 resolverGraphcool 中的 Hooks 用于同步的数据校验与数据转换。你可以把某个 hook 关联到 GraphQL API 的某个 mutation在 mutation 真正执行之前Graphcool 平台会先执行该 hook 函数函数可以选择转换传入的 mutation 参数也可以在校验规则被违反时抛错。迁移到 Prisma 后这些逻辑全部移入应用层——即你的 GraphQL Server 实现之中具体位置是createUser这样的 resolver 内部。数据校验Data validation迁移示例场景不允许name少于两个字母的User节点被创建。Graphcool Framework 中的写法把下述函数关联到 Graphcool GraphQL API 的createUsermutation 上通过返回值中的error字段表达校验失败通过data字段透传合法数据event { if (event.data.name.length 2) { return { error: The provided name ${event.data.name} is too short. A name must have at least two letters. } } return { data: event.data } }Prisma 中的写法校验逻辑移入应用层 resolver校验失败直接throw new Error(...)通过后调用 Prisma 生成的客户端context.db.mutation.createUser真正写入数据原文档代码中info前缺少一个闭合括号此处为可运行版本function createUser(parent, { name }, context, info) { if (name.length 2) { throw new Error(The provided name ${name} is too short. A name must have at least two letters.) } return context.db.mutation.createUser({ data: { name } }, info) }注意这里context.db即 Prisma 客户端实例它由datamodel自动生成相关实现可参考仓库中的 prisma-client-lib。错误信息通过 GraphQL 标准的Error机制返回给客户端而不是像 Graphcool 那样约定一个{ error }返回结构。数据转换Data transformation迁移示例场景name字段统一以全大写形式存储。Graphcool Framework 中的写法event { const uppercaseName event.data.name.toUppercase() return { data: uppercaseName } }Prisma 中的写法同样的逻辑放在createUserresolver 里先转换再落库function createUser(parent, { name }, context, info) { const uppercaseName name.toUppercase() return context.db.mutation.createUser({ data: { name: uppercaseName } }, info) }提示原文档中toUppercase()为笔误JavaScript 的正确方法名是String.prototype.toUpperCase()迁移到生产代码时请使用后者。无论哪种写法核心模式一致——所有入库前的加工都发生在 resolver 的调用链上Prisma 客户端只负责执行最终的数据变更。Resolver Functions 的迁移从 schema 扩展 JS 函数到普通 resolverGraphcool 中的 Resolver Functions 用于扩展自动生成的 CRUD API 能力典型场景包括认证如signup、loginmutation、集成第三方服务、包装 REST API 等。下文以包装 REST API为例基于 Graphcool Framework 的rest-wrapper示例调用https://dog.ceo/api/breed/${breedName}/images/random端点随机返回一张犬种图片 URL。Graphcool Framework 的组成在 Graphcool 中一个 resolver function 由两部分组成用 SDL 编写的schema 扩展schema extension用 JavaScript 编写的resolver 实现resolver implementation。schema 扩展需要扩展Query类型并定义一个新的根字段供客户端发起查询type RandomBreedImagePayload { url: String! } extend type Query { randomBreedImage(breedName: String!): RandomBreedImagePayload! }resolver 实现从传入的event中取出breedName参数调用上述 REST 端点并保证返回数据符合RandomBreedImagePayload的结构require(isomorphic-fetch) module.exports event { const { breedName } event.data const url https://dog.ceo/api/breed/${breedName}/images/random return fetch(url) .then(response response.json()) .then(responseData { const randomBreedImageData responseData.message const randomBreedImage { url: randomBreedImageData } return { data: randomBreedImage } }) }Prisma 的写法纯应用层 resolver与 Hooks 类似Graphcool Resolver Functions 的能力在 Prisma 中不再由平台承担而是直接在应用层实现。应用 schema 中仍需定义对应的根字段type RandomBreedImagePayload { url: String! } extend type Query { randomBreedImage(breedName: String!): RandomBreedImagePayload! }resolver 则成为你的 GraphQL Server 实现中的一个普通函数与 Prisma 客户端无关纯业务代码function(parent, { breedName }, context, info) { const url https://dog.ceo/api/breed/${breedName}/images/random return fetch(url) .then(response response.json()) .then(responseData { const randomBreedImageData responseData.message const randomBreedImage { url: randomBreedImageData } return { data: randomBreedImage } }) }对比可见事件驱动的module.exports event ...形态变成了标准 GraphQL resolver 的(parent, args, context, info)形态参数从event.data解构改为直接从 resolver 的第二个参数解构。整个迁移过程中业务实现本身几乎原样保留变化的只是挂载方式。Server-side Subscriptions 的迁移从 managed function 到 webhook服务端订阅server-side subscription在 Prisma 中延续了与 GraphQL Subscription 等价的能力与 API你可以使用相同的过滤器filter只订阅感兴趣的事件。二者的差别在于事件投递机制。在 Graphcool Framework 中处理函数可以是平台托管的managed function也可以是 webhook而在 Prisma 中函数无法再以 managed function 形式托管必须通过webhook配置——指向你自己部署的 HTTP 端点例如 AWS Lambda、Google Cloud Functions、Zeit Now 等。关于订阅的完整语义可参考 服务端订阅概述Prisma 会持续监听数据变更在满足条件时执行关联的订阅查询再通过 webhook 把事件载荷推送给你的端点。下文示例基于 Graphcool Framework 的subscriptions示例改造当新的User节点被创建时自动为一篇新文章生成标题。订阅查询两种框架下共用同一份Graphcool 中配置一个服务端订阅需要两个组成部分一段GraphQL 订阅查询定义订阅什么事件、事件发生时想收到什么数据一个handlermanaged function 或 webhook在事件发生时被调用。下面的订阅查询表达当一个新的User节点被**创建CREATED**时触发 handler事件载荷携带新User的id与namecreateFirstArticle.graphqlsubscription { User(filter: { mutation_in: [CREATED] }) { node { id name } } }Graphcool Frameworkmanaged function 形态Graphcool 中把 handler 指定为 managed functioncreateFirstArticle.jsconst { fromEvent } require(graphcool-lib) module.exports event { // Retrieve payload from event const { id, name } event.data.User.node // Create Graphcool API (based on graphql-request) const graphcool fromEvent(event) const api graphcool.api(simple/v1) // Create variables for mutation const title My name is ${name}, and this is my first article! const variables { authorId: id, title } // Create mutation const createArticleMutation mutation ($title: String!, $authorId: ID!) { createArticle(title: $title, authorId: $authorId) { id } } // Send mutation with variables return api.request(createArticleMutation, variables) }注意传入的event结构严格遵循订阅查询的形状如下所示node内的id与name正是订阅查询中请求的字段{ data: { User: { node: { id: cj8wscby6nl7u0133zu7c8a62, name: Sarah } } } }Graphcool 在graphcool.yml中通过functions键配置该订阅函数指向订阅查询文件与 managed function 的实现文件functions: createFirstArticle: type: subscription query: src/createFirstArticle.graphql handler: code: src/createFirstArticle.jsPrismawebhook 形态的订阅配置迁移到 Prisma 后订阅仍然配置在服务根配置文件prisma.yml中但 YAML 键发生了变化且 handler只能指向 webhooksubscriptions: createFirstArticle: query: src/createFirstArticle.graphql webhook: https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev/createFirstArticle该示例假定你已经把一个 serverless 函数部署到了https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev/createFirstArticle这个 HTTP 端点。部署在端点上的函数收到 POST 请求后从事件载荷中取出User.node数据执行与上节相同的创建第一篇文章逻辑原先由graphcool-lib的fromEvent提供的能力现在由 webhook 接收到的 HTTP 请求体承担。webhook 配置的两种形态根据仓库文档 prisma.yml 的 YAML 结构 中的subscriptions一节subscriptions属性接收一个对象每个订阅至少包含query必填订阅查询文件的路径webhook必填被调用的 webhook 信息。如果没有自定义 headers可以直接把 URL 字符串赋给webhook如上例如果需要携带 HTTP headers则webhook是一个包含url与headers的对象。无 headers 的简写形式subscriptions: sendWelcomeEmail: query: database/subscriptions/sendWelcomeEmail.graphql webhook: https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev/sendWelcomeEmail带 headers 的完整形式可用于 webhook 端点的鉴权如Authorization、Content-Typesubscriptions: sendWelcomeEmail: query: database/subscriptions/sendWelcomeEmail.graphql webhook: url: https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev/sendWelcomeEmail headers: Authorization: ${env:MY_ENDPOINT_SECRET} Content-Type: application/json内联查询与自定义变量query除了指向.graphql文件也可以直接内联一段订阅查询参考 服务端订阅示例 中的完整prisma.yml配置subscriptions: userChangedEmail: webhook: url: http://example.org/sendSlackMessage headers: Content-Type: application/json Authorization: Bearer cha2eiheiphesash3shoofo7eceexaequeebuyaequ1reishiujuu6weisao7ohc query: | subscription { user(where: { mutation_in: [UPDATED] }) { node { name email } } }同时subscriptions中的值也支持self变量引用——可以把 webhook 端点与查询目录抽象为custom变量再复用参见 02-YAML-Structure.md 中的custom示例。源码视角CLI 如何解析订阅配置Prisma CLI 在解析prisma.yml时由 PrismaDefinition.ts 中的getSubscriptions()方法统一处理订阅配置其行为与上述文档完全吻合可作为配置合法性的源码级依据webhook可以是字符串直接作为 URL或对象取其url字段若为对象则通过transformHeaders把headers转换为请求头列表query若以.graphql结尾会被当作相对prisma.yml所在目录的文件路径处理若文件不存在会抛出形如Subscription query path provided in subscription name in prisma.yml does not exist.的错误若存在则读取文件内容作为订阅查询解析结果被整理为{ name, query, headers, url }结构的函数输入FunctionInput供后续部署流程使用。也就是说从源码结构可以推断CLI 只负责把订阅定义翻译成订阅查询 webhook URL headers三元组真正的事件检测、载荷构造与 HTTP 投递由 Prisma 服务端完成。迁移自查清单与后续参考完成三类函数迁移后建议按如下清单核对Hooks 是否全部落地到 resolver所有原先挂在 mutation 上的校验/转换逻辑确认已移入对应 resolver 的调用链且通过抛Error表达校验失败Resolver Functions 的 schema 扩展是否保留应用 schema 中的扩展根字段如randomBreedImage需要保留仅实现层从事件函数改为标准 resolverSubscriptions 是否已切换到 webhookgraphcool.yml的functions配置已改为prisma.yml的subscriptions配置handler 从 managed function 改为自部署的 HTTP 端点必要时配置headers完成端点鉴权订阅查询文件路径是否存在query指向的.graphql文件必须真实存在源码会校验并报错且订阅查询的字段形状决定 webhook 收到的载荷结构。本文聚焦函数体系的迁移数据建模与 GraphQL API 形态的对应关系、认证鉴权策略、文件处理与服务器托管方案的迁移分别参见迁移指南中的 02-Data-Modelling GraphQL-API.md、03-Authentication Authorization.md、05-File-Handling.md 与 06-Server-Hosting.md。如需查阅订阅 webhook 的完整行为语义与触发示例 mutation可继续阅读 服务端订阅概述。赞分享后端数据库GraphQL【免费下载链接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]项目地址https://gitcode.com/gh_mirrors/pr/prisma1点击查看免费下载相关推荐Graphcool 迁移到 PrismaHooks、Resolver Functions 与 Server-side Subscriptions 函数能力迁移完整指南Graphcool 迁移到 PrismaHooks、Resolver Functions 与 Server side Subscriptions 函数能力迁移后端数据库GraphQLGraphcool 到 Prisma 的 Functions 迁移指南Hooks、Resolver 与 Server-side Subscriptions 的完整落地方案Graphcool 到 Prisma 的 Functions 迁移指南Hooks、Resolver 与 Server side Subscriptions 的后端数据库GraphQLPrisma 迁移指南四从 Graphcool Framework 迁移函数能力Hooks、Resolver Functions 与 Server-side SubscriptionsPrisma 迁移指南四从 Graphcool Framework 迁移函数能力Hooks、Resolver Functions 与 Server si后端数据库GraphQL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考