REST API 完全指南:实体与 Location 接口详解)
Backstage 软件目录Software CatalogREST API 完全指南实体与 Location 接口详解【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage本文面向需要将外部系统接入 Backstage 软件目录、或希望深入理解目录数据如何被查询与维护的开发者。Backstage 软件目录后端提供了一套基于 JSON 的 REST API外部系统可以通过这套接口查询实体Entities、管理 Location、触发刷新与校验等操作。读完本文你将掌握by-query谓词过滤、字段裁剪、游标分页、全文检索等核心能力的完整用法并能结合仓库源码理解其底层实现。总览API 的形态与访问前提软件目录Software Catalog是 Backstage 中用于建模软件及其所有者组件、API、系统、资源、用户、组等的核心服务。其后端暴露的是一套基于 JSON 的 REST API供外部系统直接调用。完整的 OpenAPI 规范定义位于仓库的 openapi.yaml约 1500 行的 OpenAPI 3.1 规范同时包含请求校验所需的全部参数与响应 schema。从功能上划分这套 API 主要分为两个大的功能组Entity实体类接口直接读取、查询、删除、刷新实体以及批量获取、校验实体Locations位置类接口管理 Location即目录数据来源的注册信息例如把某个 YAML 文件或 Git 仓库注册为目录的数据源。注意官方文档明确说明这份页面目前只覆盖 API 中最常用的一部分仍在持续完善中。如需最权威、最完整的定义请以 openapi.yaml 为准。基准 URLBase URL文档中出现的所有 URL 路径都假定位于某个指向你目录实例的基准 URL 之上。例如文档给出路径为/entities本地开发时目录通常位于http://localhost:7007/api/catalog那么完整 URL 就是http://localhost:7007/api/catalog/entities。生产环境中的实际 URL 因组织而异但常见的形态是应用配置中的backend.baseUrl加上/api/catalog后缀。这也是大多数 Backstage 部署中目录后端的标准挂载路径。认证方式部分或全部端点可能接受或要求携带Authorization头值为Bearer token其中的 token 应为由 Backstage 的 identity API 返回的 Backstage token。从 openapi.yaml 的securitySchemes可以看到该 API 定义了一个名为JWT的 HTTP Bearer 安全方案bearerFormat: JWT且每个路径都同时声明了匿名{}与带 JWT 两种安全选项说明部分接口在未认证时也可能可用具体取决于部署的权限策略。另外从 createRouter.ts 可以看到目录支持catalog.readonly配置项开启后目录会进入只读模式禁止写入类操作。实体Entities接口实体类接口读取的是最终实体final entities——即所有处理processing与拼接stitching流程完成之后的输出结果而非最初被摄取ingested的原始数据。关于这一过程与两者区别的详细说明可参阅 The Life of an Entity。这意味着一个实体只有在走完整个处理管线并落入最终实体集合后才会通过目录 API 对外可见。关系Relation响应格式目录 API 的响应中使用targetRef字段表示关系目标。文档特别强调已弃用的target对象以及catalog.enableRelationsCompatibility设置已被移除。如果外部目录 API 消费者仍在读取relation.target请改为使用relation.targetRef。targetRef的值是一个完整的实体引用entity reference其格式为[kind:][namespace/]name的完整形态例如group:default/ops。关于引用格式的完整说明参见 Entity References。在 openapi.yaml 的EntityRelationschema 中targetRef与type均为必填字段印证了这一响应约定。GET /entities/by-query—— 分页查询实体这是查询实体的主力端点支持以下查询参数参数作用默认值filter选择实体的子集详见过滤小节无fields只选择每个实体数据结构的一部分字段裁剪返回完整实体limit限制返回的实体数量20orderField决定实体的排序方式详见排序小节按内部uidfullTextFilterTerm/fullTextFilterFields按文本过滤实体全文检索见全文过滤小节cursor用于获取下一批/上一批实体的游标分页无totalItems是否计算响应中的totalItems字段取值为include默认或excludeinclude其中totalItems参数在 openapi.yaml 中有详细说明对于大型目录计算总数可能比较昂贵如果调用方不需要例如只做装饰性展示的游标分页 UI可以传入exclude跳过统计。未来还可能新增近似模式等取值。响应为如下形式的 JSON{ items: [{ kind: Component, metadata: { name: foo } }], totalItems: 4, pageInfo: { nextCursor: a-cursor, prevCursor: another-cursor } }其中items是分页过滤后的实体列表totalItems是符合条件的实体总数pageInfo中携带用于继续翻页的游标。过滤Filtering你可以传入一个或多个过滤集合filter sets每个集合由若干条件组成。同一集合内的条件全部满足才为真条件之间是 AND 关系只要至少一个过滤集合为真实体就会进入结果集集合之间是 OR 关系。示例/entities/by-query?filterkinduser,metadata.namespacedefaultfilterkindgroup,spec.type 返回匹配以下条件的实体 过滤集合 1: 条件 1: kind user AND 条件 2: metadata.namespace default OR 过滤集合 2: 条件 1: kind group AND 条件 2: spec.type 存在每个条件要么是key形式要么是keyvalue形式。前者断言某个键存在值不限后者断言该键存在且具有特定值。所有检查都是大小写不敏感的。在所有情况下key 都是针对实体数据某一片段的简化 JSON 路径路径的每一段是对象的一个键遍历时也会深入数组内部。有两个特殊形式数组中的简单值项如字符串匹配的等价形式是键为该项字符串、值为字符串true的键值对关系可以使用relations.typetargetRef形式对关系进行匹配。看一个简化的例子来说明这个概念。对于下面的实体数据{ a: { b: [c, { d: 1 }], e: 7 } }以下任一条件都能匹配它aa.ba.b.ca.b.ctruea.b.da.b.d1a.ea.e7更多贴近真实场景的例子返回所有孤儿实体orphaned/entities/by-query?filtermetadata.annotations.backstage.io/orphantrue返回所有用户和组/entities/by-query?filterkinduserfilterkindgroup返回所有 service 类型的组件/entities/by-query?filterkindcomponent,spec.typeservice返回所有带java标签的实体/entities/by-query?filtermetadata.tags.java返回ops组的全部成员用户注意这里使用的是该组的完整引用/entities/by-query?filterkinduser,relations.memberofgroup:default/ops全文过滤Full Text Filtering通过fullTextFilterTerm查询参数可以对实体字段进行文本搜索。它会对实体 YAML 字段中的值执行大小写不敏感的 substring 匹配。需要特别注意默认行为当未指定fullTextFilterFields参数时搜索会作用于当前的排序字段来自orderField如果连排序字段也未设置则作用于metadata.uid。这意味着不显式指定字段时搜索可能不会命中你预期的字段。要控制搜索范围请通过fullTextFilterFields查询参数传入逗号分隔的实体字段路径列表fullTextFilterTerm—— 要搜索的文本大小写不敏感、子串匹配fullTextFilterFields—— 要搜索的实体字段路径列表逗号分隔例如metadata.name,metadata.title示例/entities/by-query?fullTextFilterTermmy-servicefullTextFilterFieldsmetadata.name,metadata.title 返回 metadata.name 或 metadata.title 包含 my-service 的实体真实场景示例按名称搜索组件/entities/by-query?filterkindcomponentfullTextFilterTermpaymentfullTextFilterFieldsmetadata.name同时跨 name 与 title 搜索/entities/by-query?filterkindsystemfullTextFilterTermplatformfullTextFilterFieldsmetadata.name,metadata.title与其他过滤器组合例如限定某个组拥有的实体/entities/by-query?filterkindcomponent,relations.ownedBygroup:default/my-teamfullTextFilterTermapifullTextFilterFieldsmetadata.name注意全文过滤与基于游标的分页是互斥的。当提供了cursor时fullTextFilterTerm和fullTextFilterFields会被忽略——游标本身已经编码了初始请求中的原始过滤参数。字段选择Field Selection默认情况下接口返回完整的实体。通过fields查询参数可以指定保留实体的哪些部分这能让响应更小、传输更快并可能让目录执行更高效的查询。参数值为逗号分隔的简化 JSON 路径列表与过滤中的路径规则相同。每个路径对应一个值或子树根的键输出时其余部分会被裁剪掉。例如指定?fieldsmetadata.name,metadata.annotations,spec会保留每个实体metadata中的name与annotations字段结果是一个至多含两个键的对象完整保留spec裁剪掉所有其他根级内容如relations。真实场景示例只返回足以构成每个实体完整 ref 的数据/entities/by-query?fieldskind,metadata.namespace,metadata.name在 openapi.yaml 中fields参数被声明为数组类型并带有两个官方示例Get name and the entire relations collectionmetadata.namerelations与 Get kind, name and namespace可供参考。排序Ordering默认情况下实体按其内部uid排序。可以通过orderField查询参数自定义排序。例如按实体名称返回/entities/by-query?orderFieldmetadata.name,asc每个参数后可以跟asc升序字典序或desc降序、反转字典序。在 openapi.yaml 中orderField被描述为[field, order]的二元组数组官方示例包括metadata.name,asc按名称升序和spec.owner,desc按 owner 降序。游标分页Pagination可以通过cursor查询参数对实体集合执行游标式分页。cursor的值会出现在响应的pageInfo属性中pageInfo: { nextCursor: a-cursor, prevCursor: another-cursor }如果nextCursor存在可以用它获取下一批实体同理如果prevCursor存在可以用它获取上一批实体。需要强调的是[filter、orderField、fullTextFilter] 与cursor是互斥的。这意味着在传入了cursor时不能更改filter、orderField、fullTextFilter中的任何一个——更改这些属性会影响分页。如果它们与cursor同时指定只有后者会被考虑。POST /entities/by-query—— 谓词式查询该端点支持与 GET 变体相同的功能但参数放在 POST body 中从而不必受 URL 长度限制的约束。此外它还支持一种更高级、更具表达力的查询格式——谓词过滤见下文。响应格式与 GET 变体完全相同。从 createRouter.ts 可以看到该路由在router.post(/entities/by-query, ...)中实现内部通过parseEntityQuery等请求解析工具处理传入的谓词表达式。通过过滤器谓词Filter Predicate查询可以在请求中传入过滤器谓词来选择目录中实体的子集。谓词由一棵可选的逻辑表达式树使用$all、$any、$not构成树的最末端是过滤集合filter sets集合内可以使用自定义匹配器如$exists、$in、$hasPrefix、$contains。下面是一个过滤器谓词表达式的例子{ query: { $all: [ { kind: Component, spec.type: { $in: [service, website] } }, { $not: { metadata.annotations.backstage.io/orphan: true } } ] } }一个过滤集合是键为点分隔路径、值为原始值字符串、数字或布尔或自定义匹配器的对象。例如一个简单的过滤集合// 对给定实体而言以下条件必须全部为真它们之间是隐式 AND { // kind 字段与字面量做大小写不敏感的匹配 kind: Component, // spec 内的 type 字段使用自定义匹配器见下文 spec.type: { $in: [service, website] } }查询的根节点始终是一个对象无论其中是否有逻辑表达式树。单个键以$符号开头的节点具有特殊含义。以下是全部逻辑运算符与匹配器$not逻辑取反。其值必须是一个单独的表达式。// 匹配 kind 不是 Component 的实体 { $not: { kind: Component, } }注意$not不能用在右侧的值匹配器中// ❌ 错误 { kind: { $not: Component } } // ✅ 正确 { $not: { kind: Component } }$all要求所有给定表达式都匹配实体。其值必须是表达式数组。// 匹配同时具有 kind Component 与 type website 的实体 { $all: [ { kind: Component }, { spec.type: website } ] }空数组总是匹配所有实体。$any要求一组表达式中至少有一个匹配给定实体。其值必须是表达式数组。// 匹配 kind 为 Component 或 type 为 website 的实体 { $any: [ { kind: Component }, { spec.type: website } ] }空数组永远不匹配任何实体。$exists断言字段的存在性。其值为true字段必须存在无论值是什么或false字段必须不存在。// 匹配没有该注解的实体忽略其值可能是什么 { metadata.annotations.backstage.io/orphan: { $exists: false }, }$in断言字段具有一组原始值中的任意一个。其值必须是字符串、数字和/或布尔值组成的数组。// 匹配 type 为 service 或 website 的实体 { spec.type: { $in: [service, website] } }匹配是大小写不敏感的。空数组永远不匹配任何实体。$hasPrefix断言字段是以某个前缀文本开头的字符串。其值是一个字符串。// 匹配 project slug 注解以 backstage/ 开头的实体 { metadata.annotations.github.com/project-slug: { $hasPrefix: backstage/ } }匹配大小写不敏感且同时捕获精确匹配与以给定前缀开头的字符串。$contains断言数组包含一个匹配给定表达式的元素。此匹配器的支持有限。一个用例是关系{ // 仅支持 type 和可选的targetRef // 且 targetRef 只支持相等或 $in relations: { $contains: { type: ownedBy, targetRef: { $in: [user:default/foo, group:default/bar] } } } }另一个用例是元素为原始值的数组例如标签{ // 适用于元素是原始值的数组字段 //通常是字符串数字和布尔值也受支持 metadata.tags: { $contains: java } }值得补充的是POST /entities/by-query的请求体在 openapi.yaml 中定义还支持与 GET 变体等价的cursor、limit、offset、orderByfieldorder其中order枚举为asc/desc、fullTextFiltertermfields、fields、totalItems等字段谓词表达式则放在query字段中。GET /entities—— 列出实体已弃用列出实体。注意此端点已弃用推荐使用GET /entities/by-query后者提供了更高效的实现和基于游标的分页。该端点支持以下查询参数filter过滤、fields字段选择、offset、limit、after分页。返回类型为 JSON 数组元素为Entity。过滤规则与by-query完全相同多个过滤集合之间为 OR集合内条件之间为 AND条件为key或keyvalue形式全部大小写不敏感key 是简化 JSON 路径遍历会深入数组数组简单值项匹配为键项、值true关系可用relations.typetargetRef形式匹配。同样的简例与真实示例同样适用把路径换成/entities前缀即可返回所有孤儿实体/entities?filtermetadata.annotations.backstage.io/orphantrue返回所有用户和组/entities?filterkinduserfilterkindgroup返回所有 service 组件/entities?filterkindcomponent,spec.typeservice返回所有带java标签的实体/entities?filtermetadata.tags.java返回ops组的成员用户注意使用组的完整引用/entities?filterkinduser,relations.memberofgroup:default/ops字段选择与by-query相同fields参数为逗号分隔的简化 JSON 路径列表保留指定的值或子树根其余部分裁剪。例如只返回足以构成完整 ref 的数据/entities?fieldskind,metadata.namespace,metadata.name排序Ordering默认情况下实体以未定义但稳定的顺序返回。可以传入一个或多个order查询参数来影响排序。每个参数以asc:升序字典序或desc:降序、反转字典序开头后跟实体键中的点分隔路径。排序大小写不敏感。如果给出了多个排序指令后出现的指令优先级更低仅在前面的指令值相等时才生效。示例/entities?orderasc:kindorderdesc:metadata.name这会先按 kind 升序排列然后在同 kind如果某 kind 有多个实体内部按名称降序排列。当给定字段在结果集内的某些实体上不存在时无论期望顺序如何缺少该字段的实体在该排序步骤中总是排到最后。分页Pagination可以传入offset和limit查询参数执行经典分页。此外还有after查询参数用于在执行游标式分页时返回上一页之后的结果。每个存在下一页数据的分页响应都会携带一个Link、relnext头指向下一页的查询路径。示例——获取第一页GET /entities?limit2 HTTP/1.1 200 OK link: /entities?limit2aftereyJsaW1pdCI6Miwib2Zmc2V0IjoyfQ%3D%3D; relnext [{metadata:{...获取下一页检测到Link头后继续GET /entities?limit2aftereyJsaW1pdCI6Miwib2Zmc2V0IjoyfQ%3D%3D HTTP/1.1 200 OK link: /entities?limit2aftereyJsaW1pdCI6Miwib2Zmc2V0Ijo0fQ%3D%3D; relnext [{metadata:{...从源码层面看GET /entities的实现值得一提createRouter.ts 中当未传入分页参数时该接口实际会走流式响应路径——内部以每批 10000 条实体为上限循环调用entitiesCatalog.queryEntities并通过createEntityArrayJsonStream将实体数组以流的形式写回客户端只有当传入分页参数时才会回退到把所有实体加载进内存的旧式慢路径。这解释了为何官方推荐改用by-query即使在该端点内部新实现也是基于queryEntities的。GET /entities/by-uid/uid—— 按 UID 获取实体根据实体的metadata.uid字段值获取单个实体。返回类型为 JSON 的单个Entity如果不存在该 UID 的实体则返回 404 错误。DELETE /entities/by-uid/uid—— 按 UID 删除实体根据实体的metadata.uid字段值删除单个实体。注意这种删除方式适用于孤儿实体orphaned entities但不适用于正在被某个 Location 活跃更新的存活live实体。请阅读下文说明。最常见的用户流程是注册一个 Location见下文然后目录会持续让自身与该 Location 及其可能衍生出的子树保持同步。这意味着目录是真实权威数据源的一个实时更新的视图。如果目录中有某种东西让实体保持存活那么用本节描述的方法删除后它很快会再次出现。要彻底移除实体通常应该转而注销unregister导致该实体出现的 Location。但如果你有一个孤儿实体——例如已经从某个Location实体中移除了对其文件的引用或者某个处理器已停止产生你的实体——那么这种删除方法是合适的。返回类型始终是空的 204 响应无论该 UID 的实体是否存在。GET /entities/by-name/kind/namespace/name—— 按引用三元组获取实体根据实体的kind、metadata.namespace、metadata.name字段值获取实体。这三个字段很特殊它们共同构成实体的唯一引用三元组。返回类型为 JSON 的单个Entity如果不存在该引用三元组的实体则返回 404。GET /entities/by-name/{kind}/{namespace}/{name}/ancestry—— 获取实体谱系按实体 ref 获取一个实体的谱系ancestry。在 openapi.yaml 中该接口的响应 schema 为EntityAncestryResponse包含rootEntityRef以及items数组其中每个元素包含entity与parentEntityRefs父实体引用数组。POST /entities/by-refs—— 批量获取实体按实体引用批量获取一组实体。这在需要高效获取大量特定实体的场景下很有用例如在 GraphQL resolver 中。请求体为如下形式的 JSON{ entityRefs: [component:default/foo, api:default/bar], fields: [kind, metadata.name] }其中每个entityRefs条目都是你想获取的实体引用。fields数组是可选的其作用与GET /entities的fields相同即只获取每个实体的某些切片。返回类型为如下形式的 JSON{ items: [{ kind: Component, metadata: { name: foo } }, null] }其中items数组与输入的entityRefs数组长度相同、顺序一致。每个元素包含对应的实体数据如果目录中不存在该 ref 对应的实体则为null。在 openapi.yaml 中该接口的响应 schema 为EntitiesBatchResponse官方示例包括按 refs 批量获取实体entityRefs传入component:default/backstage、api:default/backstage以及只获取实体的metadata.annotations。另外该端点还接受一个可选的filter查询参数。POST /refresh—— 刷新实体刷新与entityRef相关的实体。请求体为如下形式的 JSON{ entityRef: string }在 createRouter.ts 中该接口的实现调用了refreshService.refresh(...)并支持在请求体中以authorizationToken字段直接携带 token 进行认证auth.authenticate未携带时则回退到httpAuth.credentials(req)。请求成功后返回 200 空响应。同时该路由在调用前后通过auditor服务记录entity-mutate审计事件并带有queryType: refresh与entityRef元数据。POST /validate-entity—— 校验实体校验传入的实体在 schema 层面没有错误。请求体为如下形式的 JSON{ location: string, entity: {} }校验失败时返回 400响应体包含errors数组每项含name与message成功时返回 200。在 createRouter.ts 中可以看到创建 OpenAPI 路由时对该路径做了特殊处理ignorePaths: /^\/validate-entity\/?$/因为该校验接口的响应类型需要由路由实现而不是请求校验器来控制。该功能也作为独立的 scaffolder action 存在createValidateEntityAction.ts。Locations位置接口Location 是目录的数据源注册信息。它描述了一个目录数据应该从哪里摄取例如一个指向catalog-info.yaml的 URL以及该位置的类型如url。注册 Location 后目录会持续从该来源同步数据并保持更新。GET /locations—— 列出所有 Location返回类型为如下形式的 JSON 数组[ { data: { id: b9784c38-7118-472f-9e22-5638fc73bab0, target: https://git.example.com/example-project/example-repository/blob/main/catalog-info.yaml, type: url } } ]在 openapi.yaml 中Location对象除了target、type、id之外还包含一个可选的entityRef字段即对应 Location 类型实体的实体引用例如location:default/generated-sha1hex。GET /locations/{id}—— 按 ID 获取 Location按 Location ID 获取单个位置。返回类型为如下形式的 JSON{ id: b9784c38-7118-472f-9e22-5638fc73bab0, target: https://git.example.com/example-project/example-repository/blob/main/catalog-info.yaml, type: url }该端点还支持PUT /locations/{id}更新已有位置的 type 与 target见 openapi.yaml。GET /locations/by-entity/{kind}/{namespace}/{name}—— 按实体获取 Location获取引用给定实体的 Location。返回类型为如下形式的 JSON{ id: b9784c38-7118-472f-9e22-5638fc73bab0, target: https://git.example.com/example-project/example-repository/blob/main/catalog-info.yaml, type: url }GET /entity-facets?facetstringfacetstringfilterstringfilterstring—— 实体刻面统计获取与给定过滤器匹配的所有实体刻面facets。返回类型为如下形式的 JSON{ facets: [ { value: string, count: 1 } ] }在 openapi.yaml 中facet是必填的数组参数官方示例包括kind按 kind 统计实体数与spec.type按 spec type 统计。响应 schemaEntityFacetsResponse中facets是一个以刻面名为键、值为{value, count}数组的对象。该端点还提供POST变体QueryEntityFacetsByPredicate可在请求体的query字段中使用谓词表达式进行过滤。POST /locations—— 添加 Location添加一个由目录摄取的 Location。如果成功响应码为HTTP/1.1 201 Created响应 JSON 形式如下{ entities: [], location: { id: b9784c38-7118-472f-9e22-5638fc73bab0, target: https://git.example.com/example-project/example-repository/blob/main/catalog-info.yaml, type: url } }如果该 Location 已经存在响应为HTTP/1.1 409 Conflict响应 JSON 形式如下{ error: { message: Location url:https://git.example.com/example-project/example-repository/blob/main/catalog-info.yaml already exists, name: ConflictError, stack: ConflictError: Location url:https://git.example.com/example-project/example-repository/blob/main/catalog-info.yaml already exists\n... }, request: { method: POST, url: /locations }, response: { statusCode: 409 } }该端点支持以下查询参数详见 openapi.yaml?dryRuntrue执行校验但不向数据库写入任何内容。如果成功通过校验响应 JSON 的entities字段会填充该位置中存在的实体?onConflictrefresh|reject控制位置已存在时的行为。reject默认返回 409 错误refresh会触发对已有 Location 实体的刷新并返回 201。请求体为{ type: ..., target: ... }LocationInput其中target与type均必填。POST /analyze-location—— 分析位置校验给定的 Location。请求体为如下形式的 JSON{ location: { type: string, target: string }, catalogFileName: string }响应类型为如下形式的 JSON{ generateEntities: [ { fields: [ { description: string, value: string, state: needsUserInput, field: string }, { description: string, value: {}, state: analysisSuggestedNoValue, field: string } ], entity: {} } ], existingEntityFiles: [ { entity: Entity, isRegistered: boolean, location: { target: string, type: string } } ] }从 openapi.yaml 的 schema 可以看出AnalyzeLocationEntityField的state枚举为analysisSuggestedValue、analysisSuggestedNoValue、needsUserInput描述了对某个字段的分析结果例如field可能是spec.owner供前端在用户需要修改时把字段重新注入实体AnalyzeLocationExistingEntity描述的是如果目标文件夹已包含 catalog info YAML 文件它们会被读取并以该形式输出使前端能告知用户已定位到这些文件并在它们尚未注册时确保一并注册。该接口通常被目录导入流程catalog import前端用来在注册前进行分析、预填充表单字段。DELETE /locations/{id}—— 删除 Location按 ID 删除 Location。成功时响应码为HTTP/1.1 204 No Content。正如删除实体一节所述这通常是移除目录中存活实体的正确方式——删除导致实体出现的 Location实体才会随之消失而不会重新出现。源码视角路由与实现佐证如果你希望进一步深入这套 API 的底层实现仓库中的关键证据包括openapi.yaml目录 API 的完整 OpenAPI 3.1 规范包含全部路径、参数kind、namespace、name、uid、cursor、after、fields、filter、offset、limit、orderField、totalItems、请求体与响应 schemaEntity、EntityRelation、EntitiesQueryResponse、LocationsQueryResponse、EntityAncestryResponse、EntitiesBatchResponse、EntityFacetsResponse、AnalyzeLocationResponse等。createRouter.ts目录路由的组装入口。它基于createOpenApiRouter生成带请求校验的路由实现要点包括catalog.readonly只读模式L115-L119、POST /refresh的认证与审计事件L122-L151、GET /entities的流式响应与回退慢路径L154-L247以及对validate-entity的校验豁免L94-L99。配套的请求解析与响应写入工具如service/request/parseEntityFilterParams、parseEntityQuery、parseEntityOrderParams、parseEntityPaginationParams以及service/response中的writeEntitiesResponse等实现了文档中描述的过滤、排序、分页与字段裁剪语义。相关文档Entity References实体引用格式理解targetRef、relations.typetargetRef过滤以及by-name/by-refs接口中的引用语义。Entity Descriptor Format实体描述格式Entity对象的结构定义kind、metadata、spec、relations。The Life of an Entity实体的生命周期理解最终实体与原始摄取数据的区别以及处理与拼接流程。软件目录文档索引目录功能的完整文档入口。【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考