Hasura Event Triggers × AWS Lambda(Go):从 echo 到 mutation 的完整实战指南

发布时间:2026/9/19 9:47:57
Hasura Event Triggers × AWS Lambda(Go):从 echo 到 mutation 的完整实战指南 Hasura Event Triggers × AWS LambdaGo从 echo 到 mutation 的完整实战指南【免费下载链接】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 仓库中 community/boilerplates/event-triggers/aws-lambda/go 的官方样板代码完整讲解如何用 Go 编写 AWS Lambda 函数作为 Hasura 事件触发器Event Trigger的 Webhook第一个示例echo用于解析并回显触发器载荷帮助理解事件数据的结构第二个示例mutation在数据库变更事件发生时通过 GraphQL Mutation 向数据库写入关联数据。读完本文你将掌握事件触发器 payload 的完整结构、AWS Lambda API Gateway 代理集成的部署步骤以及如何在 Webhook 中调用 Hasura GraphQL Mutation 实现「基于事件的写库逻辑」。一、背景Event Triggers 与 Serverless WebhookHasura GraphQL Engine 会在数据库表发生INSERT/UPDATE/DELETE时异步触发事件Event Trigger并将事件载荷以 HTTP 请求的形式发送到你配置的 Webhook 端点。整个事件触发与 Serverless 函数的架构示意见 community/boilerplates/event-triggers/README.md仓库内附有架构图assets/basic-event-triggers-arch-diagram.png。在 aws-lambda 目录 的说明中目前 Go 语言已覆盖两个核心用例用例目录用途Go 支持echo回显触发器载荷帮助理解事件 payload 及其解析方式✅mutation在插入/更新事件时通过 GraphQL Mutation 写入关联数据✅部署前需要两个前置条件一个开通计费的 AWS 账户以及一个已经运行起来的 Hasura GraphQL Engine 实例Postgres 数据源。二、echo 示例解析并回显触发器载荷echo是最简单的入门示例其目的只有一个把 Hasura 发送过来的事件载荷解析成 Go 结构体再把它原样或经简单加工后回显给调用方。通过它你可以直观地看到事件 payload 长什么样、字段如何映射。2.1 准备测试表在 Hasura 控制台的Data页签创建一张表notes: id: Integer (auto-increment) note: Text Primary key: id这张表将作为事件触发器监听的对象之后对它的任意写操作都会触发 Webhook 调用。2.2 创建 AWS Lambda 函数按照 echo/README.md 的步骤登录 AWS 管理控制台打开 AWS Lambda 控制台。在Get Started区域选择Create a function。选择Author from scratch。为 Lambda 指定Name。将Runtime选为go 1.x。在Role中选择Create new role from template(s)。在Role name中填写角色名称Policy Templates留空。构建并上传代码到 AWS Lambda运行仓库提供的构建脚本bash build.sh在 Lambda 控制台上传生成的echo.zip。点击Save保存更改。按照 AWS 官方文档api-gateway-create-api-as-simple-proxy-for-lambda创建一个带Lambda proxy integration的 API作为 Lambda 的访问入口。2.3 在 Hasura 中添加触发器进入 Hasura 控制台的Events页签添加一个触发器Add Trigger。为该触发器勾选全部insert、update、delete操作。将上一步创建的 AWS Lambda API 端点粘贴为Webhook。之后每次对notes表执行写操作Hasura 就会把事件载荷 POST 到这个 API 端点。2.4 源码解析载荷结构体与事件分发echo的完整实现位于 echo.go。它先用三个结构体把 Hasura 事件载荷「翻译」成 Go 类型type TableStruct struct { Name string json:name } type EventData struct { Old map[string]interface{} json:old New map[string]interface{} json:new } type EventStruct struct { Operation string json:op Data EventData json:data } type HasuraEvent struct { Table *TableStruct json:table Event *EventStruct json:event Op string json:op }几个值得注意的映射关系table包含触发事件的表名namemutation 示例中还会出现schema字段event.op本次操作类型取值为INSERT/UPDATE/DELETEevent.data.old变更前的行数据DELETE/UPDATE时存在event.data.new变更后的行数据INSERT/UPDATE时存在顶层op与event.op语义一致的冗余字段HasuraEvent中也一并保留了。入口 Handler 使用github.com/aws/aws-lambda-go/events的APIGatewayProxyRequest/APIGatewayProxyResponse类型这是 Lambda 与 API Gateway 代理集成时的标准签名func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { log.Printf(Processing Lambda request %v\n, request.Body) body : HasuraEvent{ Table: TableStruct{}, Event: EventStruct{}, } err : json.Unmarshal([]byte(request.Body), body) if err ! nil { message : map[string]string{ message: Unable to parse Hasura Event, } responseBody, _ : json.Marshal(message) return events.APIGatewayProxyResponse{ Body: string(responseBody), StatusCode: 400, }, nil } // ... }解析失败时返回400把错误信息以 JSON 形式写回响应体成功解析后按表名与操作类型做分支处理if body.Table.Name notes { switch body.Event.Operation { case INSERT: message fmt.Sprintf(New note %v inserted, with data: %v, data.New[id], data.New[note]) case UPDATE: message fmt.Sprintf(New note %v updated, with data: %v, data.New[id], data.New[note]) case DELETE: message fmt.Sprintf(New note %v delete, with data: %v, data.Old[id], data.Old[note]) } }这里体现了事件处理的一个通用模式INSERT/UPDATE读取data.NewDELETE读取data.Old。注意echo.go源码中EventData.Old字段的 json tag 写作jsonnew缺少冒号这是样板代码中的一处笔误实际运行时以json.Unmarshal行为为准——在你自己实现时请按json:old书写。最后以message序列化为响应体返回main()中通过lambda.Start(Handler)注册入口。三、mutation 示例事件驱动写库mutation示例展示了事件触发器的典型进阶场景当note表发生变更时自动把变更内容以新行写入note_revision表形成修订记录。这等价于在数据库写操作之外编排「由事件驱动的二次写入」是审计日志、快照、统计等业务的基础模式。3.1 准备两张表按照 mutation/README.md 创建两张表Table name: note Columns: id Integer auto-increment note Text Primary key: idTable name: note_revision Columns: id Integer auto-increment note Text note_id Integer update_at Timestamp, default: now() Primary key: id其中note_revision就是每次事件发生时被写入的「修订表」。3.2 创建 AWS Lambda 并配置环境变量Lambda 的创建步骤与 echo 示例基本一致Author from scratch、Runtime 选go 1.x、创建角色、bash build.sh后上传mutation.zip但多了一个关键步骤在 Designer 面板中为 Lambda 添加环境变量HGE_ENDPOINT值为你的 Hasura GraphQL Engine 端点。HGE_ENDPOINT是 Webhook 回调 GraphQL Engine 时使用的地址。由于 Lambda 运行在 AWS 内网实际部署时该值通常需要填写可从 AWS 访问到的 HGE 公网地址或经过 VPC / 网关可达的地址这是本示例能否成功执行 Mutation 的关键前提。随后同样创建带 Lambda proxy integration 的 API并在 Hasura 的Events页签添加触发器勾选全部 insert/update/delete 操作把 API 端点粘贴为 Webhook。3.3 源码解析环境变量、载荷校验与 GraphQL Mutationmutation的完整实现位于 mutation.go。它定义了比 echo 更完整的事件结构体覆盖了id、event、table含schema、trigger全部顶层字段type HasuraEvent struct { ID string json:id Event json:event Table json:table Trigger json:trigger }其中trigger.name即触发器的名称如note_revision_triggertrigger.id是触发器的唯一标识。环境变量读取与兜底校验包级变量HGE_ENDPOINT在函数初始化时通过os.Getenv(HGE_ENDPOINT)读取Handler 入口先检查它是否为空为空则通过constructErrorResponse返回错误信息var HGE_ENDPOINT os.Getenv(HGE_ENDPOINT) func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { if len(HGE_ENDPOINT) 0 { return constructErrorResponse(map[string]string{ message: HGE Endpoint not defined in environment variable, }) } // ... }constructErrorResponse统一负责把错误消息编码为 JSON 响应体并在序列化失败时降级为500。载荷关键字段校验解析事件后从event.data.old取出被更新行的idnote_id从event.data.new取出新的note文本任一字段缺失都会返回错误响应note_id, ok : event.Data.Old[id] if !ok { return constructErrorResponse(map[string]string{message: invalid payload: note id not found}) } note, ok : event.Data.New[note] if !ok { return constructErrorResponse(map[string]string{message: invalid payload: note not found}) }构造并执行 GraphQL Mutation示例将待执行的 mutation 定义为常量字符串并通过 HTTP POST 发送到HGE_ENDPOINTconst MUTATION_UPDATE_NOTE_REVISION mutation updateNoteRevision ($object: note_revision_insert_input!) { insert_note_revision (objects: [$object]) { affected_rows returning { id } } } 注意这里使用的note_revision_insert_input类型是 Hasura 依据表结构自动生成的输入类型。构造请求时把note_id从 JSON 反序列化来的数字是float64这里做了类型断言与note组装为变量payload : map[string]interface{}{ query: MUTATION_UPDATE_NOTE_REVISION, variables: map[string]interface{}{ object: map[string]interface{}{ note_id: note_id.(float64), note: note.(string), }, }, } b : new(bytes.Buffer) json.NewEncoder(b).Encode(payload) res, err : http.Post(HGE_ENDPOINT, application/json; charsetutf-8, b)请求体是标准 GraphQL-over-HTTP 格式queryvariablesContent-Type 为application/json; charsetutf-8。响应解码为map[string]interface{}后原样回传给 API Gateway最终由 Hasura 控制台展示给用户。3.4 端到端测试与预期输出mutation 示例的 README 给出了完整的测试方法进入 Hasura 控制台的Data页签找到note表并打开Browse rows页签编辑一条已有记录然后检查note_revision表是否新增了对应修订行同时可以在触发器的「请求与响应」面板中查看 Webhook 的调用详情。更新note表时Hasura 发送给 Webhook 的触发器载荷request如下{ event: { op: UPDATE, data: { old: { note: note1, id: 1 }, new: { note: note1 updated, id: 1 } } }, created_at: 2018-10-02T06:38:22.67311Z, id: f57a1c79-72ba-4c19-8791-37d1b9616bcf, trigger: { name: note_revision_trigger, id: 5d85cbd1-c134-45ce-810c-7ecd3b4fc1ee }, table: { schema: public, name: note } }这份载荷完整展示了事件触发器的真实结构顶层event包含操作类型op与data.old/data.new新旧数据created_at是事件产生时间id是事件唯一 IDtrigger给出触发器名与 IDtable给出数据库 schema 与表名。这正是 echo 示例结构体定义所对应的实际 JSON。Webhook 执行 GraphQL Mutation 成功后返回的响应如下{ data: { insert_note_revision: { affected_rows: 1, returning: [ { id: 2 } ] } } }可以看到insert_note_revision返回affected_rows: 1与新增行的id证明修订记录已成功写入note_revision表。四、两个示例的对比与通用要点维度echomutation核心目的理解并回显事件载荷事件发生时通过 GraphQL 写库监听表notesnote额外配置无Lambda 环境变量HGE_ENDPOINT关键依赖encoding/json、aws-lambda-go/events额外依赖net/http、bytes、os关键代码位置echo.gomutation.go从两个示例可以提炼出编写 Hasura Event Trigger Webhook 的通用要点签名统一使用aws-lambda-go的APIGatewayProxyRequest/APIGatewayProxyResponse保持 API Gateway 代理集成兼容lambda.Start(Handler)注册入口。载荷解析先行事件 JSON 中的数字字段如id反序列化后是float64写入 GraphQL 变量时需做类型断言OLD/NEW是map[string]interface{}取值前务必做存在性检查两个示例都演示了错误兜底。写库走 GraphQLWebhook 不直接连数据库而是通过HGE_ENDPOINT调用 Hasura 自动生成的 mutation如insert_note_revision这样权限、校验、返回结构都由 GraphQL Engine 统一处理。错误即响应所有失败路径缺环境变量、JSON 解析失败、字段缺失、HTTP 调用失败都构造为带message的 JSON 响应返回便于在 Hasura 触发器日志中排查。五、进一步阅读事件触发器的完整概念与工作方式event-triggers/overview.mdx如何创建触发器及配置 Webhookevent-triggers/create-trigger.mdx事件载荷的字段说明event-triggers/payload.mdx其他语言实现Node.js、Python、Ruby与更多云平台样板community/boilerplates/event-triggers/aws-lambda、community/boilerplates/event-triggers/README.md事件触发器的架构图与通用说明community/boilerplates/event-triggers/assets如果你需要推送通知FCM/APNS、ETL 数据转换等其他用例也可以参考仓库中push-notification、etl等目录Go 语言尚未覆盖欢迎按 aws-lambda/README.md 中的清单补充贡献。【免费下载链接】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),仅供参考