资讯动态

graphql-ruby 订阅触发(Triggers)指南:用 .trigger 从应用向 GraphQL 客户端推送更新

发布时间:2026/10/13 6:04:34 来源:尧图企业网站定制
后端API设计【免费下载链接】graphql-rubyRuby implementation of GraphQL项目地址https://gitcode.com/gh_mirrors/gr/graphql-ruby点击查看免费下载本篇指南聚焦 graphql-ruby 的订阅触发机制当业务应用发生某个事件例如新增一篇博客、评论了一条帖子时如何通过MySchema.subscriptions.trigger将更新推送给正在监听该事件的 GraphQL 客户端。你将掌握trigger四个核心参数name、arguments、object、scope:的用法、基于context的定向投递Scope机制以及更新触发时订阅校验Validation的开关与定制方法并结合仓库源码理解其背后的事件主题topic生成、参数规范化与序列化原理。订阅触发的基本用法从应用代码中你可以通过.trigger把更新推送给 GraphQL 客户端。事件是按名字触发的而且这个名字必须与 Subscription Type订阅根类型 上的某个字段一一对应。例如# 用新博客文章更新系统 MySchema.subscriptions.trigger(:post_added, {}, new_post)其中MySchema是你的 GraphQL Schema 类.subscriptions返回挂载在该 Schema 上的订阅管理器通过use SomeSubscriptions安装。trigger的完整签名见 lib/graphql/subscriptions.rb为def trigger(event_name, args, object, scope: nil, context: {})各参数的含义如下参数说明name即event_name事件名称对应 Subscription 根类型上的字段名字段名默认按 camelCase 规则与 GraphQL 字段名匹配详见下文名称与参数规范化arguments订阅字段的参数哈希。例如客户端在订阅某篇帖子下的评论时触发事件应传{post_id: comment.post_id}只有参数匹配的订阅才会收到更新object本次订阅更新的根对象root object将作为该订阅字段解析时的根值scope:用于隐式限定哪些客户端会收到更新见下文Scope定向投递context:可选触发时附带的上下文哈希会被并入更新执行的上下文名称与参数规范化事件如何与订阅字段匹配trigger并非简单地把名字拿来即用而是会经过两层规范化见 lib/graphql/subscriptions.rb第一步名称查找与 camelize。先按原样verbatim在Subscription根类型上查找字段如果找不到就通过normalize_name把名字 camelize例如:post_added→postAdded后再查一次。normalize_name的默认实现就是调用Schema::Member::BuildType.camelizelib/graphql/subscriptions.rb你也可以在自定义订阅管理器的子类中覆盖该方法改变转换规则。第二步参数规范化。通过normalize_arguments处理触发参数把 Symbol 键转成 String必要时对参数名做 camelize与字段的参数定义对齐自动回填参数定义中带默认值的参数使触发参数与订阅查询的参数一致对于loads:参数会替换为对应的 argument keyword如果收到的参数在字段定义中不存在会抛出错误。两层规范化共同保证了事件能准确命中订阅字段。当事件名与字段不匹配、或参数与字段参数定义不匹配时会抛出GraphQL::Subscriptions::InvalidTriggerError定义于 lib/graphql/subscriptions.rb错误消息形如No subscription matching trigger: hidden_event (looked for Subscription.hiddenEvent) Cant trigger Subscription.event, received undefined arguments: scream. (Should match arguments of Subscription.event.)以上错误行为都有对应测试用例参见 spec/graphql/subscriptions_spec.rb。Scope把更新定向投递给特定客户端默认情况下触发事件会推送给所有监听该字段且参数匹配的订阅。如果只想发送给部分客户端可以用scope:收窄触发器的覆盖范围。原理基于 query context 的隐式条件Scope 建立在查询上下文之上订阅建立时context:中的某个值被用作该订阅的 scope触发更新时.trigger(... scope:)必须传入等价的值客户端才会收到更新。该值会通过GraphQL::Subscriptions::Serialize序列化后参与主题topic的计算。第一步在订阅类中声明subscription_scope要声明某个订阅主题是带作用域的可以在 Subscription 类上增加subscription_scope选项class Subscriptions::CommentAdded Subscription::BaseSubscription description A comment was added to one of the viewers posts # 对某个 viewer 而言只要其帖子新增了评论就会触发 subscription_scope :current_user_id # ... endsubscription_scope接收一个 Symbol该 Symbol 会被当作 key 去context中查找具体的 scope 值lib/graphql/schema/subscription.rb。更多细节见 Subscription Classes 指南中的 Scope 一节。第二步订阅操作提供对应的 context 值订阅操作应该在执行时带上这个 scope 对应的上下文值# current_user_id 将作为某些订阅的 scope MySchema.execute(query_string, context: { current_user_id: current_user.id })第三步事件发生时以 scope: 触发应用里发生事件后把同样的 scoping 值通过scope:传进去# 新增了一条评论 comment post.comments.create!(attrs) # 通知作者 author_id post.author.id MySchema.subscriptions.trigger(:comment_added, {}, comment, scope: author_id)由于该触发器带了scope:只有 scope 值匹配的订阅者才会收到更新。在 spec/graphql/subscriptions_spec.rb 的allows context-scoped subscriptions测试中可以看到完整行为me: 1的订阅者只收到scope: 1的触发me: 2的订阅者只收到scope: 2的触发互不干扰。源码视角scope 如何参与主题计算在 lib/graphql/subscriptions/event.rb 的Event构造中scope 值取自scope参数或订阅建立时context[subscription_scope]。随后Event.serialize会调用订阅类的topic_for生成主题字符串——默认实现为Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments])lib/graphql/schema/subscription.rb即把「scope 字段名 参数」序列化成一个字符串作为该订阅的唯一标识。只有topic完全一致的订阅者才会收到更新这就是定向投递的底层机制。GraphQL::Subscriptions::Serialize.dump_recursive对 scope 值的序列化规则lib/graphql/subscriptions/serialize.rb为数组元素用:连接、Hash 按key:value连接、实现to_gid_param的对象用 GlobalID 参数、实现to_param的对象用to_param、其余对象直接to_s。因此 scope 可以是 Symbol、String、数字、数组、Hash 乃至 ActiveRecord 对象。补充字段级 subscription_scope 与必填校验subscription_scope除了在订阅类上声明也可以直接在字段上配置。从源码看GraphQL::Schema::Field支持subscription_scope:参数并提供了对应读写方法lib/graphql/schema/field.rb、lib/graphql/schema/member/has_fields.rb测试中也有通过Schema.get_field(Subscription, myEvent).subscription_scope :me直接赋值的用法spec/graphql/subscriptions_spec.rb。当某个订阅声明了subscription_scope但初始订阅时context中没有对应值、或更新触发时没有传scope:Event构造会抛出GraphQL::Subscriptions::SubscriptionScopeMissingErrorlib/graphql/subscriptions/event.rb错误消息提示Subscription.field (Subscriptions::CommentAdded) requires a scope: value to trigger updates (Set subscription_scope ..., optional: true to disable this requirement)如果希望该 scope 变成可选的即允许不带 scope 的订阅/触发可以在声明时加上optional: trueclass Subscriptions::CommentAdded Subscription::BaseSubscription subscription_scope :current_user_id, optional: true # ... end从源码结构看lib/graphql/schema/subscription.rboptional:会被记录到subscription_scope_optional?供Event在缺失 scope 时决定是否放行。Validation更新触发时是否重新校验订阅默认情况下当一次触发导致订阅发送更新时graphql-ruby 会重新校验该订阅查询见 lib/graphql/subscriptions.rb 的execute_options[:validate] validate_update?(...)。如果你确定 Schema 不会发布破坏性变更可以关闭这项校验来减少更新求值的额外开销use SomeSubscriptions, validate_update: false这里SomeSubscriptions指的是你使用的具体订阅后端实现类例如GraphQL::Subscriptions::ActionCableSubscriptionsuse GraphQL::Subscriptions::ActionCableSubscriptions, validate_update: false。validate_update:选项在订阅管理器的initialize中被读取并存储lib/graphql/subscriptions.rb。更精细的控制覆盖validate_update?除了全局关闭你还可以通过覆盖validate_update?方法按每次更新的实际情况决定是否校验。该方法在 lib/graphql/subscriptions.rb 中定义默认返回构造时传入的validate_update它接收query:、context:、root_value:、subscription_topic:、operation_name:、variables:关键字参数。例如仅在 context 中显式要求校验时才进行校验class SometimesSkipSubscriptions InMemoryBackend::Subscriptions def validate_update?(context:, **_rest) !!context[:validate_update] end end对应测试见 spec/graphql/subscriptions_spec.rb覆盖该方法后validate_update: false的 Schema 在触发更新时跳过校验而validate_update: true的 Schema 每次触发都会执行校验。触发后的完整流程一次trigger调用背后的完整链路均可在源码中追踪Subscriptions#trigger规范化事件名与参数构造Subscriptions::Eventlib/graphql/subscriptions.rb调用execute_all(event, object)把事件派发给所有匹配订阅者该方法在基类中抛出RequiredImplementationMissingError由各后端实现例如 ActionCable 实现 会把事件广播到对应 stream后端实现通过read_subscription读取订阅时保存的查询字符串、变量、context 与操作名重新执行查询execute_updatelib/graphql/subscriptions.rb结果经deliver投递给对应客户端若期间触发了unsubscribe或查询结果为no_update则相应清理或跳过投递。小结用MySchema.subscriptions.trigger(name, arguments, object)从应用推送更新name必须匹配 Subscription Type 上的字段参数会经过 camelize 与默认值回填等规范化处理用subscription_scopecontext:trigger(... scope:)实现定向投递scope 值通过GraphQL::Subscriptions::Serialize序列化后参与 topic 计算是只通知相关客户端的关键用use SomeSubscriptions, validate_update: false关闭更新时的重复校验以降低开销或覆盖validate_update?按需控制事件名或参数不匹配会抛出InvalidTriggerErrorscope 缺失会抛出SubscriptionScopeMissingError可用optional: true放宽。赞分享后端API设计【免费下载链接】graphql-rubyRuby implementation of GraphQL项目地址https://gitcode.com/gh_mirrors/gr/graphql-ruby点击查看免费下载相关推荐graphql-ruby-client 使用指南GraphQL-Ruby 官方 JavaScript 客户端的安装、OperationStore 同步与多端订阅实战graphql ruby client 使用指南GraphQL Ruby 官方 JavaScript 客户端的安装、OperationStore 同步与多端订后端API设计如何在15分钟内完成OpenCore EFI配置面向初学者的终极简化指南如何在15分钟内完成OpenCore EFI配置面向初学者的终极简化指南 你是否曾经因为复杂的黑苹果配置而头疼不已 面对ACPI补丁、内核扩展、SMBI开发工具CLIwiliwili 教程三步在掌机和电脑跑通手柄B站客户端wiliwili 教程三步在掌机和电脑跑通手柄B站客户端 wiliwili 是一款专为手柄用户设计的第三方 B站 客户端支持 Nintendo Switch音视频桌面应用上一篇Simple Icons终极安全指南合规使用品牌图标的完整法律要点解析下一篇Stendhal任务攻略从新手到大师的10大必做经典任务创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑