2.4 API层:REST与GraphQL


2.4 API层:REST与GraphQL

本节摘要:DataHub 对外提供两套程序化接口:REST 面向简单直接的实体读写,GraphQL 面向一次取齐关联实体的复合查询。本节讲清两者的能力分工与适用场景,给出可套用的调用示例,并说明元数据消费方(调度系统、质量工具、内部平台)该如何选路。本节是第 2 章的出口:架构与数据流最终都要落到这些接口上才能被外部世界使用,第 4 章的接入开发与第 5 章的血缘应用都建立在本节之上。

两套接口,两种性格

把 DataHub 的接口层想象成测绘局的对外服务窗口:一个是"单事项窗口",进门办一件事,办完即走;另一个是"综合窗口",一次递交一张关联清单,所有材料一次取齐。REST 是前者,GraphQL 是后者。

REST 接口围绕实体与 Aspect 组织,路径语义直白:读一个实体、写一个 Aspect、提交一条血缘。它的优势是每个请求意图单一、调试直观、任何 HTTP 客户端都能调用。GraphQL 接口则允许在一个请求里声明"我要这张表的详情、它的上游两跳、每跳实体的负责人",服务端一次性组装返回。代价是需要学习查询语法,且复合查询的深度与广度要自己控制,避免一不小心让服务端做一次全图遍历。

选路的原则一句话:写元数据、简单读用 REST;带关系的复合读、界面级聚合用 GraphQL。

用 REST 写一条元数据

最常见的程序化写入场景是外部工具回填元数据:质量平台想把今天的校验结果挂到表上,调度系统想补一条任务与表的依赖。这类写入用 REST 完成最省事。下面是一个最小可用的提交骨架,实际使用时替换实体键与内容即可:

{ "proposalType": "UPSERT", "entityType": "dataset", "entityUrn": "urn:li:dataset:urn:li:dataPlatform:mysql,sales.orders,PROD", "aspectName": "datasetProperties", "aspectValue": { "value": { "description": "订单主表,按天分区,来源为业务库同步", "customProperties": { "owner_team": "trade-data", "tier": "P1" } } } }

三个字段是理解这套接口的钥匙:entityType 加 entityUrn 定位到具体实体,aspectName 指定要动它的哪一块属性,aspectValue 携带新内容。UPSERT 语义表示存在则更新、不存在则创建。写错了 aspectName 会收到模型校验错误,错误信息会列出该实体类型合法的 Aspect 清单——按清单改,不要凭感觉换字段名。

从接口读回一个实体同样直接:按 URN 请求实体接口,返回该实体的全部 Aspect;若只关心某一块,加上 Aspect 名过滤可以显著减小响应体。批量场景(比如导出一个业务域的所有表)改用列表接口配分页参数,避免一次拉全量。

用 GraphQL 一次取齐血缘邻域

界面上的"表详情加上下游血缘加负责人"三联视图,如果用 REST 实现要发多次请求并自行拼装;GraphQL 允许一次声明全部需求。查询骨架长这样:

query { dataset(urn: "urn:li:dataset:urn:li:dataPlatform:hive,dwd.orders,PROD") { name description lineage { upstream { entities { urn type } } downstream { entities { urn type ... on Dataset { name owners { owner { urn } } } } } } } }

这段查询的可读性接近自然语言:取这张表的名字与描述,取它的上游实体列表,再取下游列表——下游每个实体额外要名字和负责人,且用条件片段声明"下游如果是数据集才取名字与负责人"。服务端负责把这棵需求树一次性解析返回。

工程上两条注意。第一,控制展开深度:血缘查询的深度参数直接决定遍历开销,界面默认浅层展开是刻意的性能保护,程序化调用时同样要克制,深挖需求改为逐层发起。第二,GraphQL 的报错是按字段返回的:一部分字段成功、一部分字段带错是合法状态,消费端要按字段判错而不是整个请求一刀切。

消费方接入的三条实践路线

路线一:工具型回写。 质量工具、调度系统这类既有平台,在各自的关键节点上回写元数据——校验完成写结果、任务运行写运行状态、发布变更写血缘。走 REST,一次一意,失败重试安全(UPSERT 天然幂等)。这是投入产出比最高的路线,两周内就能让平台的元数据从"静态快照"变成"活的状态"。

路线二:目录型集成。 公司内部有自己的门户或研发平台,想把 DataHub 的搜索与详情能力嵌进去。走 GraphQL 做聚合查询,门户后端做一层薄封装处理认证与限流。注意不要把 GraphQL 查询直接暴露给浏览器端任意拼装——查询形状应由服务端定义,前端只能选参数,否则遍历深度失控会拖垮图服务。

路线三:批量消费。 数据资产周报、元数据质量对账这类场景,按天批量拉取实体清单。优先用带分页的列表接口加字段过滤,避免全量实体详情拉取;大批量迁移场景再考虑导出工具。批量消费最常见的坑是把详情接口当列表接口用——循环单发请求,速率一高就撞限流,列表接口配分页才是正路。

⚠️ 接口写入绕过了界面上的部分交互保护(比如所有权认领流程)。给外部系统开写入权限时,建议为其分配独立账号,出问题时可以按账号追溯变更来源,也能一键收权。

调用方的自保三则

接口是契约,调用方也要有契约精神。三则自保做法,让外部系统在平台升级与故障时少受伤。

重试要讲礼貌。 写入失败重试时,UPSERT 的幂等性保证了安全,但重试节奏要有退避:连续快速重试不仅加剧平台负担,还可能在平台限流时把自己打进更深的失败。指数退避加最大重试次数,是所有调用方的默认配置。

读结果要做瘦身。 GraphQL 查询里只声明真正消费的字段——把整个实体结构一把梭地要回来,看似省事,实则放大响应体与解析开销,平台侧字段调整时你的解析器也更容易碎。声明式查询的好处本来就在于"要多少、要什么自己说"。

报错要留现场。 收到模型校验错误时,把请求体与完整错误响应记进自己的日志——平台侧的模型可能演进(3.3 的三色规则),半年后排查"为什么那条写入不进来了",有现场的日志三十秒结案,没现场的只能对着猜测复现。

清单要有版本。 外部系统依赖的接口形状(用到的字段、枚举值)维护成一份显式清单,平台升级时对照清单做回归。接口能力是只增不减的假设不可靠——字段改名、枚举收敛都可能随版本发生,清单是你与平台之间唯一可核对的约定。

本节要点回顾

  • 性格分工:REST 是单事项窗口,适合写与简单读;GraphQL 是综合窗口,适合带关系的复合读。
  • REST 钥匙:实体类型加 URN 定位、Aspect 名指定块、UPSERT 幂等;校验错误会列出合法 Aspect。
  • GraphQL 纪律:控制血缘展开深度、按字段判错;查询形状由服务端定义,不放任前端拼装。
  • 三条路线:工具回写走 REST、门户集成走 GraphQL、批量对账走分页列表,各取所需。
  • 权限治理:外部写入用独立账号,变更可追溯、权限可单独回收。

至此第 2 章把平台从里到外看了一遍。下一章进入建模世界:这张图上的实体与关系是如何被定义、扩展和演进的。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U