使用 AWS Lambda 作为 Hasura GraphQL Engine 事件触发器 Webhook 的 Node.js 实战指南
2026/9/19 19:47:50 网站建设 项目流程

使用 AWS Lambda 作为 Hasura GraphQL Engine 事件触发器 Webhook 的 Node.js 实战指南

【免费下载链接】graphql-engineBlazing fast, instant realtime GraphQL APIs on all your data with fine grained access control, also trigger webhooks on database events.项目地址: https://gitcode.com/gh_mirrors/gr/graphql-engine

导读

本文基于 Hasura GraphQL Engine 官方仓库中的 aws-lambda/nodejs8/echo 示例,完整讲解如何把 AWS Lambda 函数接入 Hasura Event Trigger,在数据库发生INSERT/UPDATE/DELETE操作时自动接收事件负载并执行异步业务逻辑。读完本文,你将掌握事件触发负载(payload)的结构、Lambda 的创建与配置步骤、index.handler的编写方式,以及如何在 Hasura Console 中把 Lambda 的 API 端点注册为 Webhook,并了解在此基础上扩展出"写回数据库"等高级用法的实现思路。

什么是 Event Trigger,为什么选择 AWS Lambda

Hasura Event Trigger 是 Hasura GraphQL Engine 提供的一种异步业务逻辑机制:当连接的数据库中某张表发生数据变更时,Hasura 会以 HTTPPOST请求将事件负载发送到你配置的 Webhook 端点(参见 docs/docs/event-triggers/overview.mdx)。Event Trigger 可配置为在表的INSERTUPDATEDELETE事件上触发,也可以在 Console 中通过按钮手动触发。

把 Webhook 部署在 AWS Lambda 上的好处在于:无需维护常驻服务器,按调用次数计费,天然适合"数据库事件 → 异步处理"这种低频、突发的调用模式。仓库 community/boilerplates/event-triggers/README.md 给出的整体架构如下:

从源码目录看,aws-lambda 下按语言组织了多个官方示例,Node.js(nodejs8)目录下包含两个用例:

目录用途
echo回显触发器负载(本文主体)
mutation在收到 insert 事件后,用 GraphQL mutation 向数据库写回关联数据

第一步:在数据库中准备notes

Event Trigger 必须挂在某张表上。官方示例使用一张简单的notes表,你可以在 Hasura Console 的 Data 页签中创建,也可以在 SQL 中执行建表语句。字段定义如下:

notes: id: int note: text

字段含义:

  • id:整数类型,作为主键(示例中默认为自增,mutation 示例中明确为Integer auto-increment);
  • note:文本类型,存放便签内容。

该表将成为后面验证事件负载的载体:插入、更新、删除notes表的数据时,对应的 Lambda 就会被触发。

第二步:理解 Event Trigger 的 Webhook 负载结构

在动手写 Lambda 之前,先理解 Hasura 发送给 Webhook 的数据格式,这是正确解析index.jsevent.body的关键。官方文档 docs/docs/event-triggers/payload.mdx 定义了完整的负载结构:

{ "payload": { "created_at": "<TIMESTAMP>", "delivery_info": { "current_retry": "<RETRY_NUMBER>", "max_retries": "<MAX_RETRIES>" }, "event": { "data": { "new": "<OBJECT_OF_COLUMNS_AND_VALUES>", "old": "<OBJECT_OF_COLUMNS_AND_VALUES|NULL>" }, "op": "<INSERT|UPDATE|DELETE|MANUAL>", "session_variables": { "x-hasura-role": "<ROLE_NAME>" }, "trace_context": { "span_id": "<SPAN_ID>", "trace_id": "<TRACE_ID>" } }, "id": "<UUID_FOR_INVOCATION>", "table": { "name": "<TABLE_NAME>", "schema": "<SCHEMA_NAME>" }, "trigger": { "name": "<TRIGGER_NAME>" } } }

核心字段说明(完整字段表见 payload.mdx):

字段类型说明
created_atString触发器被调用的时间戳
delivery_info.current_retry/max_retriesInteger当前重试次数 / 最大重试次数
event.opString操作名,取值仅为INSERTUPDATEDELETEMANUAL
event.data.newObject事件相关的新数据,键值对为"列名-值"
event.data.oldObject 或null事件相关的旧数据,不适用时为null
event.session_variablesObject触发事件的用户的 session 变量(Postgres 下可用)
idString本次调用的 UUID
table.name/table.schemaString表名 / schema 名
trigger.nameString触发器名

不同操作下new/old的取值规则(Postgres):

  • INSERToldnullnew为插入的行;
  • UPDATEold为更新前的值,new为更新后的值;
  • DELETEold为被删除的行,newnull
  • MANUALoldnullnew为当前行。

此外,官方文档还说明:UPDATE事件只在"新数据与旧数据不同"时才投递;表计算字段不会包含在负载中。Webhook 返回2xx状态码被视为调用成功,其他状态码会按重试配置触发重试;若响应携带Retry-After头且状态码为非2xx,则事件会在指定秒数后再次投递,可用于限流/防抖。

第三步:在 AWS 上创建 Lambda 函数

按 echo/README.md 的步骤在 AWS 控制台完成配置:

  1. 在 AWS Lambda 控制台创建一个函数;
  2. 运行时选择Node.js 8.10
  3. 选择"start from scratch"(从头开始创作)
  4. 添加API Gateway作为触发器;
  5. 在 API Gateway 中新建一个 API(这样 Lambda 就获得了一个可供 Hasura 调用的 HTTP 端点);
  6. 把下文 index.js 的代码粘贴进函数编辑器,处理函数即为index.handler

环境说明:示例基于 Node.js 8.10 编写(当时 Lambda 的主流运行时)。当前 AWS 已提供更新的 Node.js 运行时,代码中的 async/await 语法在更高版本中同样可用,运行时版本升级不影响示例逻辑本身。

第四步:深入解析index.handler源码

这是本次示例的核心文件:echo/index.js。它演示了如何解析 Hasura 事件负载并按操作类型回显消息:

exports.handler = async (event) => { let response = {} try { let { table: { name }, event: { op, data } } = event.body; response.statusCode = 200; if (name === "notes" && op === "INSERT") { response.body = `New note ${data.new.id} inserted, with data: ${data.new.note}`; } else if (name === "notes" && op === "UPDATE") { response.body = `Note ${data.new.id} updated, with data: ${data.new.note}`; } else if (name === "notes" && op === "DELETE") { response.body = `Note ${data.old.id} deleted, with data: ${data.old.note}`; } return response } catch (e) { response.statusCode = 400; response.body = "cannot parse hasura event"; return response } };

逐段解读其设计:

1. 从event.body解构负载

let { table: { name }, event: { op, data } } = event.body;

注意这里解构的是event.body(Lambda 通过 API Gateway 收到的 HTTP 请求体),而不是event本身。对照上面的负载结构:table.name对应payload.table.nameevent.op对应payload.event.opdata对应payload.event.data。需要强调的是,仓库中这份示例对event.body直接解构,说明作者在创建 API Gateway 触发器时未开启 Lambda 代理集成(若开启代理集成,event.body会是 JSON 字符串,需要先JSON.parse才能解构);你在实际部署时需根据自己的 API Gateway 配置做相应调整。

2. 按操作类型分支处理

  • INSERTdata.new携带新行,读取data.new.iddata.new.note
  • UPDATEdata.new携带更新后的行;
  • DELETE:此时data.newnull,必须读取data.old.iddata.old.note——这是示例中体现"不同操作读取不同数据段"的关键细节。

3. 异常兜底

整个解构与分支放在try/catch中,一旦负载格式不符(例如 Webhook 被非 Hasura 的请求调用),返回400"cannot parse hasura event"。这符合官方对 Webhook 响应约定:2xx表示成功,其他状态码会触发重试或告警。

第五步:在 Hasura Console 中添加 Event Trigger

完成 Lambda 部署并记下 API Gateway 的端点 URL 后,回到 Hasura Console 配置触发器:

  1. 进入Events页签,点击添加触发器;
  2. 选择notes表,并勾选全部操作:insert、update、delete
  3. 把 AWS Lambda 的API 端点 URL粘贴为Webhook地址;
  4. 保存后,触发器的状态变为活跃(active)。

至此,链路打通:任何对notes表的插入、更新、删除操作,都会触发 Hasura 向你的 Lambda 端点发送POST请求,Lambda 解析负载并按操作类型返回响应消息。可以在 Console 的 Events 页签中看到每次事件的投递记录、响应状态码与重试信息,用于验证整条链路是否工作正常。

进阶:在 Lambda 中通过 GraphQL Mutation 写回数据库

echo示例只做"回显",同目录下的 mutation/index.js 展示了更有业务价值的模式:在收到事件后,调用 Hasura 的 GraphQL 端点向数据库写入关联数据。其部署步骤比 echo 多两步(详见 mutation/README.md):

  1. mutation目录执行npm install安装依赖(使用node-fetch发起 HTTP 请求);
  2. 执行zip -r hge-mutation.zip .打成 zip 包,在 Lambda 中上传该 zip(而非粘贴代码);
  3. 在 Lambda 环境变量中配置两项:
    • ACCESS_KEY:你初始化 Hasura GraphQL Engine 时配置的 admin secret;
    • HGE_ENDPOINT:HGE 实例运行的 URL。

代码的核心逻辑是:当notes表发生 insert 事件时,用旧行数据构造一个 GraphQL mutation,把note_revision表的记录写回数据库:

const query = ` mutation updateNoteRevision ($noteId: Int!, $data: String!) { insert_note_revision (objects: [ { note_id: $noteId, note: $data } ]) { affected_rows } } `; exports.handler = async (event) => { try { const qv = { noteId: event.body.event.data.old.id, data: event.body.event.data.old.note }; const result = await fetch(hgeEndpoint + '/v1/graphql', { method: 'POST', body: JSON.stringify({ query: query, variables: qv }), headers: { 'Content-Type': 'application/json', 'x-hasura-admin-secret': accessKey }, }); // ... } };

这段代码演示了三个要点:

  • 用环境变量保存敏感信息ACCESS_KEYHGE_ENDPOINT通过process.env读取,避免硬编码;
  • 以 admin secret 调用 GraphQL API:请求头中的x-hasura-admin-secret用于绕过权限校验执行写操作;
  • mutation 携带变量variables中的noteIddata与 GraphQL 查询的$noteId$data一一对应,而数据来源正是事件负载中event.data.old的旧行。

对应的note_revision表需要在 Hasura Console 中预先创建:

Table name: note_revision Columns: id: Integer auto-increment note: Text note_id: Integer (foreign key to notes.id) update_at: Timestamp, default `now()`

扩展阅读与仓库参考

  • 事件触发器官方文档:事件触发负载结构见 docs/docs/event-triggers/payload.mdx,总览见 docs/docs/event-triggers/overview.mdx;
  • AWS Lambda 目录总览与多语言支持情况见 community/boilerplates/event-triggers/aws-lambda/README.md,同一用例还提供 Go、Python、Ruby 等语言实现(如 python/echo/echo.py);
  • 其他 Serverless 平台示例:仓库还包含 Azure Functions、Google Cloud Functions、Netlify Functions、Zeit Now 等平台的同款 boilerplate,可对照参考。

本文的完整示例代码与部署文档均位于仓库 community/boilerplates/event-triggers/aws-lambda/nodejs8/ 目录下,可直接查看、复制并据此部署。

【免费下载链接】graphql-engineBlazing fast, instant realtime GraphQL APIs on all your data with fine grained access control, also trigger webhooks on database events.项目地址: https://gitcode.com/gh_mirrors/gr/graphql-engine

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询