应用程序接口
软件目录后端有一个基于 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
.
查询实体 支持以下查询参数,详见下一节:
过滤器
,只选择所有实体的一个子集 *字段
,只选择每个实体的完整数据结构的一部分 * "限制",限制返回实体的数量(默认为 20 个) *排序字段
,决定实体的顺序 * 全文本过滤器](#全文本过滤),通过文本过滤实体 * [游标
,检索下一批或上一批实体
返回类型为 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 thejava
tag:/entities/by-query?filter=metadata.tags.java
* Return all users who are members of theops
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
只保留name
和annotations
的字段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
] andcursor
are mutually exclusive. This means that, it isn't possible to change any of [filter
,orderField
,fullTextFilter
] when passingcursor
as query parameters, as changing any of these properties will affect pagination. If any offilter
,orderField
,fullTextFilter
is specified together withcursor
, only the latter is taken into consideration.
GET /entities
列出实体。
注该端点已被弃用,取而代之的是GET /entities/by-query
提供了更高效的实现和基于游标的分页。
该端点支持以下查询参数,具体说明见下文各节:
- 用于分页的
offset
、limit
和after
。
返回类型为 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
只保留name
和annotations
的字段metadata
是一个最多有两个键的对象),保留整个spec
不变,并删除所有其他根,如relations
.
再举些现实世界中可用的例子:
- 只返回足以形成每个实体完整 ref 的数据:
/entities?fields=kind,metadata.namespace,metadata.name
。
订购
默认情况下,实体将以未定义但稳定的顺序返回。 您可以输入一个或多个order
查询参数来影响排序。
每个参数都以asc:
表示升序词性顺序,或desc:
表示递减(反向)词典顺序,后面是实体键的点分隔路径。 排序不区分大小写。 如果给出多个排序指令,后面的指令优先级较低(只有当优先级较高的指令具有相同值时才会应用)。
例如
/entities?order=asc:kind&order=desc:metadata.name
这将首先按种类升序排列输出结果,然后在每个种类内(如果给定种类不止一个)按名称降序排列输出结果。 如果给定的字段不存在于结果集中的所有实体中,那么在该特定排序步骤中,没有该字段的实体将始终排在最后,无论所需的排序是什么。
分页
您可以通过offset
和limit
查询参数对实体集进行经典分页。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.namespace
和metadata.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