Skip to main content

应用程序接口

软件目录后端有一个基于 JSON 的 REST API,可被外部系统利用。 本页介绍了它的外形和功能。

概览

应用程序接口表面由几组不同的功能组成,每组功能都有专门的章节介绍。

** 注:** 本页仅描述了 > 应用程序接口中最常用的部分,是一项正在进行中的工作。

本文中的所有 URL 路径都假定是在指向目录安装的某个基本 URL 的顶部。 例如,如果下面某个部分给出的路径是/entities目录位于http://localhost:7007/api/catalog在本地开发期间,完整的 URL 将是http://localhost:7007/api/catalog/entities实际 URL 可能因组织而异,尤其是在生产过程中,但通常是您的backend.baseUrl在应用程序配置中,加上/api/catalog在最后。

部分或全部端点可能接受或需要一个Authorization标头的Bearer令牌,然后该令牌应是由身份 API.

实体

这些端点直接处理实体的读取。 它暴露的是最终实体--即所有处理和拼接过程的输出,而不是原始的原始输入实体数据。 请参见实体的生命了解有关这一过程和区别的更多详情。

GET /entities/by-query.

查询实体 支持以下查询参数,详见下一节:

返回类型为 JSON,格式如下

{
"items": [{ "kind": "Component", "metadata": { "name": "foo" } }],
"totalItems": 4,
"pageInfo": {
"nextCursor": "a-cursor",
"prevCursor": "another-cursor"
}
}

过滤

您可以输入一个或多个与每个实体匹配的过滤集。 每个过滤集都是若干个条件,这些条件必须全部匹配才能为真(条件之间实际上有一个 AND)。 至少有一个过滤集必须为真,实体才能成为结果集的一部分(过滤集之间实际上有一个 OR)。

例如

/entities/by-query?filter=kind=user,metadata.namespace=default&filter=kind=group,spec.type

Return entities that match

Filter set 1:
Condition 1: kind = user
AND
Condition 2: metadata.namespace = default

OR

Filter set 2:
Condition 1: kind = group
AND
Condition 2: spec.type exists

每个条件的形式可以是<key>或表格<key>=<value>第一种形式断言存在某个键(具有任意值),第二种形式断言该键存在并具有某个值。 所有检查都是大小写形式不敏感.

在所有情况下,键都是给定实体数据中的一个简化 JSON 路径。 路径的每个部分都是一个对象的键,遍历也是通过数组进行的。 有两种特殊形式:

  • 简单值类型(如字符串)的数组项与键值对匹配,其中键是字符串项,值是字符串 true * 关系可通过 relations.<type>=<targetRef> 形式匹配

让我们看一个简化的例子来说明这个概念:

{
"a": {
"b": ["c", { "d": 1 }],
"e": 7
}
}

这符合以下任何一种情况:

  • a * a.b * a.b.c * a.b.c=true * a.b.d * a.b.d=1 * a.e * a.e=7

再举些现实世界中可用的例子:

  • Return all orphaned entities: /entities/by-query?filter=metadata.annotations.backstage.io/orphan=true * Return all users and groups: /entities/by-query?filter=kind=user&filter=kind=group * Return all service components: /entities/by-query?filter=kind=component,spec.type=service * Return all entities with the java tag: /entities/by-query?filter=metadata.tags.java * Return all users who are members of the ops group (note that the full reference of the group is used): /entities/by-query?filter=kind=user,relations.memberof=group:default/ops

全文过滤

TODO

字段选择

默认情况下会返回完整的实体,但您也可以通过fields这样可以使响应更小,传输速度更快,并允许目录执行更高效的查询。

查询参数值是一个以逗号分隔的简化 JSON 路径列表,如上图所示。 每个路径对应一个值的键,或一个希望在输出中保留的子树根的键。 其余的将被剪除。 例如,指定?fields=metadata.name,metadata.annotations,spec只保留nameannotations的字段metadata是一个最多有两个键的对象),保留整个spec不变,并删除所有其他根,如relations.

再举些现实世界中可用的例子:

  • 只返回足以形成每个实体完整 ref 的数据:/entities/by-query?fields=kind,metadata.namespace,metadata.name

订购

默认情况下,实体按其内部 uid 排序。orderField查询参数来影响排序。

例如,按名称返回实体:

/entities/by-query?orderField=metadata.name,asc

每个参数后面可以跟asc表示升序词性顺序,或desc表示降序(反向)词性顺序。

分页

您可以通过cursor查询参数在实体集中执行基于游标的分页。cursor将在pageInfo财产

"pageInfo": {
"nextCursor": "a-cursor",
"prevCursor": "another-cursor"
}

如果nextCursor按照同样的方法,如果prevCursor存在,可用于检索前一批实体。

  • filter, for selecting only a subset of all entities * fields, for selecting only parts of the full data structure of each entity * limit for limiting the number of entities returned (20 is the default) * orderField, for deciding the order of the entities * fullTextFilter NOTE: [filter, orderField, fullTextFilter] and cursor are mutually exclusive. This means that, it isn't possible to change any of [filter, orderField, fullTextFilter] when passing cursor as query parameters, as changing any of these properties will affect pagination. If any of filter, orderField, fullTextFilter is specified together with cursor, only the latter is taken into consideration.

GET /entities

列出实体。

该端点已被弃用,取而代之的是GET /entities/by-query提供了更高效的实现和基于游标的分页。

该端点支持以下查询参数,具体说明见下文各节:

返回类型为 JSON,是一个由实体.

过滤

您可以输入一个或多个与每个实体匹配的过滤集。 每个过滤集都是若干个条件,这些条件必须全部匹配才能为真(条件之间实际上有一个 AND)。 至少有一个过滤集必须为真,实体才能成为结果集的一部分(过滤集之间实际上有一个 OR)。

例如

/entities?filter=kind=user,metadata.namespace=default&filter=kind=group,spec.type

Return entities that match

Filter set 1:
Condition 1: kind = user
AND
Condition 2: metadata.namespace = default

OR

Filter set 2:
Condition 1: kind = group
AND
Condition 2: spec.type exists

每个条件的形式可以是<key>或表格<key>=<value>第一种形式断言存在某个键(具有任意值),第二种形式断言该键存在并具有某个值。 所有检查都是大小写形式不敏感.

在所有情况下,键都是给定实体数据中的一个简化 JSON 路径。 路径的每个部分都是一个对象的键,遍历也是通过数组进行的。 有两种特殊形式:

  • 简单值类型(如字符串)的数组项与键值对匹配,其中键是字符串项,值是字符串 true * 关系可通过 relations.<type>=<targetRef> 形式匹配

让我们看一个简化的例子来说明这个概念:

{
"a": {
"b": ["c", { "d": 1 }],
"e": 7
}
}

这符合以下任何一种情况:

  • a * a.b * a.b.c * a.b.c=true * a.b.d * a.b.d=1 * a.e * a.e=7

再举些现实世界中可用的例子:

返回所有孤儿实体:/entities?filter=metadata.annotations.backstage.io/orphan=true * 返回所有用户和组:/entities?filter=kind=user&filter=kind=group * 返回所有服务组件:/entities?filter=kind=component,spec.type=service * 返回所有带有java标记的实体:/entities?filter=metadata.tags.java * 返回所有属于ops组成员的用户(注意使用组的完整引用):/entities?filter=kind=user,relations.memberof=group:default/ops * 返回所有属于ops组成员的用户(注意使用组的完整引用):`/entities?

字段选择

默认情况下会返回完整的实体,但您也可以通过fields这样可以使响应更小,传输速度更快,并允许目录执行更高效的查询。

查询参数值是一个以逗号分隔的简化 JSON 路径列表,如上图所示。 每个路径对应一个值的键,或一个希望在输出中保留的子树根的键。 其余的将被剪除。 例如,指定?fields=metadata.name,metadata.annotations,spec只保留nameannotations的字段metadata是一个最多有两个键的对象),保留整个spec不变,并删除所有其他根,如relations.

再举些现实世界中可用的例子:

  • 只返回足以形成每个实体完整 ref 的数据:/entities?fields=kind,metadata.namespace,metadata.name

订购

默认情况下,实体将以未定义但稳定的顺序返回。 您可以输入一个或多个order查询参数来影响排序。

每个参数都以asc:表示升序词性顺序,或desc:表示递减(反向)词典顺序,后面是实体键的点分隔路径。 排序不区分大小写。 如果给出多个排序指令,后面的指令优先级较低(只有当优先级较高的指令具有相同值时才会应用)。

例如

/entities?order=asc:kind&order=desc:metadata.name

这将首先按种类升序排列输出结果,然后在每个种类内(如果给定种类不止一个)按名称降序排列输出结果。 如果给定的字段不存在于结果集中的所有实体中,那么在该特定排序步骤中,没有该字段的实体将始终排在最后,无论所需的排序是什么。

分页

您可以通过offsetlimit查询参数对实体集进行经典分页。after查询参数,用于在执行基于游标的分页时,在上一页结果之后返回下一页结果。

每个有下一页数据的分页响应都会有一个Link,rel="next"标题指向下一页的查询路径。

例如:获取第一页:

GET /entities?limit=2
HTTP/1.1 200 OK
link: </entities?limit=2&after=eyJsaW1pdCI6Miwib2Zmc2V0IjoyfQ%3D%3D>; rel="next"

[{"metadata":{...

获取下一页,因为我们检测到了Link

GET /entities?limit=2&after=eyJsaW1pdCI6Miwib2Zmc2V0IjoyfQ%3D%3D
HTTP/1.1 200 OK
link: </entities?limit=2&after=eyJsaW1pdCI6Miwib2Zmc2V0Ijo0fQ%3D%3D>; rel="next"

[{"metadata":{...

GET /entities/by-uid/<uid>

根据实体的metadata.uid字段值。

返回类型是 JSON,作为单个实体如果没有具有该 UID 的实体,则会出现 404 错误。

DELETE /entities/by-uid/<uid>

删除实体metadata.uid字段值。

请阅读下文。

最常见的用户流程是注册一个位置(见下文),然后目录会根据该位置和可能从中产生的子树不断更新自己。 这意味着目录是实际权威数据源的实时更新视图。 如果有什么东西让实体在目录中 "存活",那么在使用本节描述的方法删除后不久,它就会重新出现。 要正确删除实体,通常需要取消注册导致实体出现的位置。

但是,如果您有一个孤儿实体,例如在从Location实体,或者如果处理器已停止生产您的实体,那么这种删除方法是合适的。

无论是否存在具有该 UID 的实体,返回类型始终是空的 204 响应。

GET /entities/by-name/<kind>/<namespace>/<name>

根据实体的kind,metadata.namespacemetadata.name它们的特殊性在于,它们构成了实体唯一的参照三胞胎。

返回类型是 JSON,作为单个实体如果没有实体具有该引用三元组,则会出现 404 错误。

POST /entities/by-refs

根据实体引用获取一批实体。 这在需要高效获取大量特定实体的情况下非常有用,例如在 GraphQL 解析器中。

请求体是 JSON 格式的

{
"entityRefs": ["component:default/foo", "api:default/bar"],
"fields": ["kind", "metadata.name"]
}

其中每个entityRefs条目是您要获取的实体 ref。fields数组是可选的,其工作方式与GET /entities字段,例如,它只用于获取每个实体的某些片段。

返回类型为 JSON,格式为

{
"items": [{ "kind": "Component", "metadata": { "name": "foo" } }, null]
}

其中items数组具有长度相同和同一顺序作为输入entityRefs每个元素都包含相应的实体数据,或null如果目录中不存在具有该 ref 的实体。

地点

GET /locations

列出地点。

响应类型为 JSON,格式为

[
{
"data": {
"id": "b9784c38-7118-472f-9e22-5638fc73bab0",
"target": "https://git.example.com/example-project/example-repository/blob/main/catalog-info.yaml",
"type": "url"
}
}
]

GET /locations/{id}

通过位置 ID 获取位置。

响应类型为 JSON,格式为

{
"id": "b9784c38-7118-472f-9e22-5638fc73bab0",
"target": "https://git.example.com/example-project/example-repository/blob/main/catalog-info.yaml",
"type": "url"
}

GET /locations/by-entity/{kind}/{namespace}/{name}

获取指向给定实体的位置。

响应类型为 JSON,格式为

{
"id": "b9784c38-7118-472f-9e22-5638fc73bab0",
"target": "https://git.example.com/example-project/example-repository/blob/main/catalog-info.yaml",
"type": "url"
}

POST /locations

添加要被目录摄取的位置。

如果成功,响应代码将为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"
}
}

如果该位置已经存在,回复将是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
}
}

支持?dryRun=true查询参数,它将执行验证,而不会向数据库写入任何内容。 如果成功通过验证,则entities字段将由位置中存在的实体填充。

DELETE /locations/<uid>

根据 ID 删除位置。 成功后的响应代码将是HTTP/1.1 204 No Content.

其他

TODO