ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Hasura Event Triggers 实战:在 AWS Lambda 上用 Java 8 构建 echo Webhook(含 payload 解析与部署全流程)

2026/9/19 20:21:10 拓冰建站 浏览量
Hasura Event Triggers 实战:在 AWS Lambda 上用 Java 8 构建 echo Webhook(含 payload 解析与部署全流程) Hasura Event Triggers 实战在 AWS Lambda 上用 Java 8 构建 echo Webhook含 payload 解析与部署全流程【免费下载链接】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本指南基于当前仓库community/boilerplates/event-triggers/aws-lambda/java/echo示例完整讲解如何为 Hasura GraphQL Engine 的 Event Triggers 编写一个运行在 AWS Lambda 上的 Java Webhook从建表、配置 Lambda、用 Maven 打包部署到解析事件负载、接入 Hasura 触发器的全流程。读完你将掌握 Event Triggers 的请求-响应协议、event.data.new/old与event.op的字段语义并能在本地直接运行该示例的单元测试验证行为。示例概览echo Webhook 做什么该 Java Lambda 示例实现的是一个「回显echo」Webhook每当notes表发生 INSERT / UPDATE / DELETE 时Hasura 会把事件负载通过 HTTP POST 发送到 Lambda 的 API Gateway 端点函数解析负载后用自然语言描述刚刚发生的操作例如New note 1 inserted, with data: aNote 2 updated, with data: bNote 1 deleted, with data: a示例位于 community/boilerplates/event-triggers/aws-lambda/java/echo目录内包含三个核心 Java 源文件、一个 Maven 构建文件pom.xml、一个 JUnit 5 单元测试及对应的事件负载样例delete.json是一个可直接运行的最小闭环示例。第一步在 Hasura 中建表Webhook 监听的数据表需要在 Hasura 连接的数据源PostgreSQL中创建。按 README 要求创建一张名为notes的表包含两个字段列名类型说明idint主键事件负载中用于区分新旧数据notetext业务字段回显消息中的「data」部分表结构信息会被 Hasura 写入每次事件的table.name字段Webhook 正是通过它判断事件来自哪张表见下文Hello.java中的$.table.name校验逻辑。第二步在 AWS 上创建 Lambda 函数README 给出了在 AWS 控制台创建函数的步骤进入 AWS Lambda 控制台点击「Create a function」。运行时Runtime选择Java 8对应示例代码中maven-compiler-plugin的source/target均为1.8见 pom.xml。选择「Author from scratch」从零开始而非使用预置模板。为函数添加API Gateway作为触发器Trigger。在 API Gateway 中为函数添加一个 API 路由Add an API该 API 的调用端点invoke URL就是稍后填给 Hasura 的 Webhook URL。第三步理解 Java 处理入口Hello.java函数入口类为example.Hello实现了 AWS Lambda 的RequestHandlerMapString, Object, MapString, Object接口Hello.java这意味着请求与响应都以Map形式表示与 API Gateway 代理集成的 JSON 请求/响应结构一一对应。处理流程拆解如下Override public MapString, Object handleRequest(MapString, Object request, Context context) { context.getLogger().log(request.toString()); // 把整个请求打到 CloudWatch MapString, Object response new HashMap(); response.put(isBase64Encoded, false); try { String requestBody (String) request.get(body); // 取 HTTP bodyJSON 字符串 response.put(body, handleRequestBody(requestBody)); // 解析并生成回显文本 response.put(statusCode, 200); } catch (Exception e) { response.put(body, e.toString()); response.put(statusCode, INTERNAL_SERVER_ERROR); // 500 } return response; }要点说明request.get(body)取出的是JSON 字符串需要再交给 JSONPath 解析response必须包含statusCode和body并显式设置isBase64Encoded为false这是 API Gateway 代理集成的响应格式要求。成功时返回200解析失败例如事件来自非notes表时返回500。根据官方事件负载文档docs/docs/event-triggers/payload.mdx只有2xx才被视为 Webhook 调用成功非2xx会触发 Hasura 按重试配置重新投递因此返回码语义不可随意。负载解析与业务分发真正的解析逻辑在handleRequestBody中private String handleRequestBody(String requestBody) { DocumentContext body JsonPath.parse(requestBody); String table body.read($.table.name); if (table ! null table.equals(notes)) { Notebook.Operation operation Notebook.Operation.valueOf(body.read($.event.op)); Note newNote body.read($.event.data.new, Note.class); Note oldNote body.read($.event.data.old, Note.class); return notebook.handleOperation(operation, newNote, oldNote); } else { throw new UnsupportedOperationException(table: table); } }这里通过 JsonPath 读取负载中的三个关键字段JSONPath 表达式对应负载字段用途$.table.name触发事件的表名校验事件来源本例只处理notes$.event.op操作类型INSERT/UPDATE/DELETE决定业务分支$.event.data.new新数据插入/更新后的行作为Note对象反序列化$.event.data.old旧数据更新前/删除的行作为Note对象反序列化模型类NoteNote.java 是行数据的 POJO 模型字段与notes表一一对应并提供标准的 getter/setter供 JSONPath 反序列化使用class Note { private Integer id; private String note; // getId / setId / getNote / setNote }业务分发器NotebookNotebook.java 通过枚举OperationINSERT、UPDATE、DELETE与switch完成操作分发String handleOperation(Operation operation, Note newNote, Note oldNote) { switch (operation) { case INSERT: return New note newNote.getId() inserted, with data: newNote.getNote(); case UPDATE: return Note newNote.getId() updated, with data: newNote.getNote(); case DELETE: return Note oldNote.getId() deleted, with data: oldNote.getNote(); default: throw new UnsupportedOperationException(operation: operation); } }注意 DELETE 分支读取的是oldNote被删除前的行而 INSERT / UPDATE 读取newNote——这与官方负载文档中「event.data.old在 DELETE 时包含被删除的行、event.data.new为null」的语义完全一致见 payload.mdx。从该示例代码也可以推断由于示例负载中的new与old使用同一个Note模型实际生产实现中更稳妥的做法是像这里一样按操作类型选择正确的数据源避免读取到null字段。第四步Maven 构建部署包README 给出的构建部署步骤在终端进入项目目录cd community/boilerplates/event-triggers/aws-lambda/java/echo说明README 原文写的是community/boilerplates/serverless-triggers/aws-lambda/java/echo而当前仓库中的真实路径为community/boilerplates/event-triggers/aws-lambda/java/echo实际使用时以后者为准。构建部署包mvn package在 AWS 控制台上传产物target/java-lambda-1.0-SNAPSHOT.jar。为什么能直接上传maven-shade-pluginpom.xml 中配置了maven-shade-plugin版本 3.2.0它在package阶段将所有依赖尤其是aws-lambda-java-core与json-path打成一个 fat/shaded JAR因此target/java-lambda-1.0-SNAPSHOT.jar可以独立部署无需在 Lambda 运行时再挂载依赖层。项目声明的关键依赖pom.xml依赖版本用途com.amazonaws:aws-lambda-java-core1.2.0RequestHandler、Context等 Lambda Java 核心接口com.jayway.jsonpath:json-path2.4.0用 JSONPath 表达式解析事件负载org.slf4j:slf4j-nop1.7.25屏蔽 SLF4J 日志绑定告警org.junit.jupiter:junit-jupiter-api5.1.0testJUnit 5 单元测试第五步接入 Hasura Event Trigger在 Hasura Console 的Events事件标签页中点击「Add Trigger」新建一个触发器。为该触发器勾选insert、update、delete全部三类操作Operations这也是本示例Notebook支持全部三种Operation的原因。将你的 AWS Lambda API Gateway 端点 URL 粘贴为Webhook地址。完成之后每当notes表发生插入、更新或删除时Hasura 就会向该端点发起POST请求。事件负载payload结构详解本示例的 Webhook 收到的是 Hasura Event Trigger 的标准负载。以仓库测试样例 delete.json 为例API Gateway 把 Hasura 的POSTbody 放在请求的body字段中其内容为{ table: { name: notes }, event: { op: DELETE, data: { new: { id: 2, note: b }, old: { id: 1, note: a } } } }对照官方负载规范docs/docs/event-triggers/payload.mdx完整负载还包含以下字段字段类型说明created_atString触发器调用时间戳delivery_info.current_retry/max_retriesInteger当前重试次数与最大重试次数event.opString操作类型INSERT、UPDATE、DELETE、MANUALevent.data.newObject新数据INSERT 时为插入的行UPDATE 时为更新后的行DELETE 时为nullevent.data.oldObject 或null旧数据UPDATE 时为更新前的行DELETE 时为被删除的行INSERT 时为nullevent.session_variablesObject触发事件的用户的x-hasura-*会话变量Postgres 数据源提供event.trace_contextObject链路追踪的span_id/trace_ididString本次调用的 UUIDtable.name/table.schemaString表名与 Schema 名trigger.nameString触发器名称另外Webhook 的响应按规范要求2xx视为成功若返回非2xx且带Retry-After头Hasura 会在指定秒数后再次投递用于节流/退避场景。这与示例中500会触发重试的设计相互印证。本地验证单元测试与测试桩示例附带 JUnit 5 单元测试 HelloTest.java无需真实 AWS 环境即可验证核心逻辑Test void handleRequestDelete() throws IOException { MapString, Object request new HashMap(); request.put(body, loadResource(delete.json)); MapString, Object response new Hello().handleRequest(request, new ContextStub()); assertEquals(200, response.get(statusCode)); assertEquals(Note 1 deleted, with data: a, response.get(body)); }测试把delete.json的内容放进请求的body字段调用真实的handleRequest断言返回码为200且回显文本为Note 1 deleted, with data: a——即读取的是event.data.old中的行id1, notea。由于Context是 AWS 接口测试使用 ContextStub.java 提供桩实现其中getLogger()返回一个把日志打到System.out的LambdaLogger对应Hello.handleRequest中context.getLogger().log(request.toString())的行为其余方法返回null或-1。运行mvn test即可执行该测试。完整实战流程回顾把上文串联起来从零到可用的完整链路是在 Hasura 数据源中创建notes表id intnote text。在 AWS 控制台创建 Java 8 Runtime 的 Lambda 函数添加 API Gateway 触发器并创建 API。用mvn package构建 shaded JAR上传target/java-lambda-1.0-SNAPSHOT.jar。编辑Hello.java的handleRequest或直接使用本示例逻辑按table.name、event.op、event.data.new/old解析并处理事件。在 Hasura Console 的 Events 页新建触发器勾选 insert/update/delete填入 Lambda 的 API 端点。对notes表执行插入/更新/删除在 Lambda 的 CloudWatch 日志与函数返回值中观察回显结果本地可用mvn test先行验证解析逻辑。如果需要进一步扩展可以参照本示例把handleOperation替换为真实的业务逻辑如调用外部 API、写审计日志、触发下游通知负载的解析骨架无需改动仓库中community/boilerplates/event-triggers目录下还提供了其他语言的 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创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考