Skip to content

Commit cdd7eff

Browse files
authored
feat(inner): add released resource lookup API (#3163)
(cherry picked from commit c8cd511)
1 parent ad9d8e3 commit cdd7eff

9 files changed

Lines changed: 209 additions & 50 deletions

File tree

src/dashboard/apigateway/apigateway/apis/v2/inner/serializers.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,20 +155,32 @@ class Meta:
155155

156156

157157
class GatewayReleasedResourceListInputSLZ(serializers.Serializer):
158-
resource_names = serializers.CharField(required=False, allow_blank=True)
159158
fields = serializers.CharField(required=False, allow_blank=True)
160159

161-
def validate_resource_names(self, value) -> list[str]:
160+
def validate_fields(self, value) -> set[str] | None:
161+
return validate_output_fields(value, RELEASED_RESOURCE_FIELDS)
162+
163+
class Meta:
164+
ref_name = "apigateway.apis.v2.inner.serializers.GatewayReleasedResourceListInputSLZ"
165+
166+
167+
class GatewayReleasedResourceLookupInputSLZ(serializers.Serializer):
168+
names = serializers.CharField()
169+
fields = serializers.CharField(required=False, allow_blank=True)
170+
171+
def validate_names(self, value) -> list[str]:
162172
return validate_comma_separated_names(
163173
value,
164-
max_count_error=_("resource_names 最多支持 {max_count} 个"),
174+
required=True,
175+
required_error=_("names 不能为空"),
176+
max_count_error=_("names 最多支持 {max_count} 个"),
165177
)
166178

167179
def validate_fields(self, value) -> set[str] | None:
168180
return validate_output_fields(value, RELEASED_RESOURCE_FIELDS)
169181

170182
class Meta:
171-
ref_name = "apigateway.apis.v2.inner.serializers.GatewayReleasedResourceListInputSLZ"
183+
ref_name = "apigateway.apis.v2.inner.serializers.GatewayReleasedResourceLookupInputSLZ"
172184

173185

174186
class _SelectableFieldsOutputSLZMixin:

src/dashboard/apigateway/apigateway/apis/v2/inner/urls.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@
8787
views.GatewayReleasedResourceListApi.as_view(),
8888
name="openapi.v2.inner.gateway.released_resource.list",
8989
),
90+
# GET /api/v2/inner/gateways/{gateway_name}/released-resources/-/lookup/
91+
path(
92+
"released-resources/-/lookup/",
93+
views.GatewayReleasedResourceLookupApi.as_view(),
94+
name="openapi.v2.inner.gateway.released_resource.lookup",
95+
),
9096
path(
9197
"permissions/",
9298
include(

src/dashboard/apigateway/apigateway/apis/v2/inner/views.py

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -243,25 +243,11 @@ class GatewayReleasedResourcePagination(BoundedLimitOffsetPagination):
243243
max_limit = INNER_BOUNDED_LIST_MAX_LIMIT
244244

245245

246-
@method_decorator(
247-
name="get",
248-
decorator=swagger_auto_schema(
249-
operation_description="获取指定网关当前已发布资源",
250-
query_serializer=serializers.GatewayReleasedResourceListInputSLZ,
251-
responses={status.HTTP_200_OK: serializers.GatewayReleasedResourceOutputSLZ(many=True)},
252-
tags=["OpenAPI.V2.Inner"],
253-
),
254-
)
255-
class GatewayReleasedResourceListApi(generics.ListAPIView):
246+
class _GatewayReleasedResourceApiMixin:
256247
serializer_class = serializers.GatewayReleasedResourceOutputSLZ
257248
permission_classes = [OpenAPIV2GatewayNamePermission]
258-
pagination_class = GatewayReleasedResourcePagination
259-
260-
def list(self, request, gateway_name, *args, **kwargs):
261-
input_slz = serializers.GatewayReleasedResourceListInputSLZ(data=request.query_params)
262-
input_slz.is_valid(raise_exception=True)
263-
data = input_slz.validated_data
264249

250+
def get_released_resources(self, request, resource_names=None):
265251
tenant_id = get_request_tenant_id(request)
266252
if tenant_id:
267253
visible = gateway_filter_by_app_tenant_id(
@@ -270,28 +256,64 @@ def list(self, request, gateway_name, *args, **kwargs):
270256
).exists()
271257
if not visible:
272258
raise Http404
273-
gateway = request.gateway
274259

275-
queryset = get_gateway_released_resources(
276-
gateway_id=gateway.id,
277-
resource_names=data.get("resource_names"),
260+
return get_gateway_released_resources(
261+
gateway_id=request.gateway.id,
262+
resource_names=resource_names,
278263
)
279-
page = self.paginate_queryset(queryset)
264+
265+
def serialize_released_resources(self, resources, fields):
280266
items = [
281267
{
282268
"id": resource.resource_id,
283269
"name": resource.resource_name,
284270
"description": (resource.data or {}).get("description", ""),
285271
"description_en": (resource.data or {}).get("description_en"),
286272
}
287-
for resource in page
273+
for resource in resources
288274
]
289-
output_slz = self.get_serializer(
290-
items,
291-
many=True,
292-
fields=data.get("fields"),
293-
)
294-
return self.get_paginated_response(output_slz.data)
275+
return self.get_serializer(items, many=True, fields=fields).data
276+
277+
278+
@method_decorator(
279+
name="get",
280+
decorator=swagger_auto_schema(
281+
operation_description="获取指定网关当前已发布资源",
282+
query_serializer=serializers.GatewayReleasedResourceListInputSLZ,
283+
responses={status.HTTP_200_OK: serializers.GatewayReleasedResourceOutputSLZ(many=True)},
284+
tags=["OpenAPI.V2.Inner"],
285+
),
286+
)
287+
class GatewayReleasedResourceListApi(_GatewayReleasedResourceApiMixin, generics.ListAPIView):
288+
pagination_class = GatewayReleasedResourcePagination
289+
290+
def list(self, request, gateway_name, *args, **kwargs):
291+
input_slz = serializers.GatewayReleasedResourceListInputSLZ(data=request.query_params)
292+
input_slz.is_valid(raise_exception=True)
293+
data = input_slz.validated_data
294+
295+
queryset = self.get_released_resources(request)
296+
page = self.paginate_queryset(queryset)
297+
return self.get_paginated_response(self.serialize_released_resources(page, data.get("fields")))
298+
299+
300+
@method_decorator(
301+
name="get",
302+
decorator=swagger_auto_schema(
303+
operation_description="按名称查询指定网关当前已发布资源",
304+
query_serializer=serializers.GatewayReleasedResourceLookupInputSLZ,
305+
responses={status.HTTP_200_OK: serializers.GatewayReleasedResourceOutputSLZ(many=True)},
306+
tags=["OpenAPI.V2.Inner"],
307+
),
308+
)
309+
class GatewayReleasedResourceLookupApi(_GatewayReleasedResourceApiMixin, generics.ListAPIView):
310+
def list(self, request, gateway_name, *args, **kwargs):
311+
input_slz = serializers.GatewayReleasedResourceLookupInputSLZ(data=request.query_params)
312+
input_slz.is_valid(raise_exception=True)
313+
data = input_slz.validated_data
314+
315+
resources = self.get_released_resources(request, resource_names=data["names"])
316+
return OKJsonResponse(data=self.serialize_released_resources(resources, data.get("fields")))
295317

296318

297319
@method_decorator(

src/dashboard/apigateway/apigateway/data/apidocs/zh/v2_inner_list_gateway_released_resources.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
多租户模式下必须通过 `X-Bk-Tenant-Id` 请求头传入当前租户 ID,否则返回 `400`。接口仅允许访问全租户网关及当前租户的单租户网关;跨租户访问统一返回 `404`,不暴露网关是否存在。
66

7-
同一资源 ID 出现在多个当前版本时只返回一个快照,默认选择版本 ID 较大的快照。若指定 `resource_names`,则先按快照名称精确过滤,再按资源 ID 去重
7+
同一资源 ID 出现在多个当前版本时只返回一个快照,默认选择版本 ID 较大的快照。按资源名称精确查询时,请使用 released resource lookup 接口
88

99
### 输入参数
1010

@@ -18,7 +18,6 @@
1818

1919
| 参数名称 | 参数类型 | 必选 | 描述 |
2020
|---|---|---|---|
21-
| resource_names | string || 资源名称列表,精确匹配,多个以逗号分隔,去重后最多 50 个 |
2221
| fields | string || 返回字段列表,多个以逗号分隔;支持 `id``name``description`,不传返回全部字段 |
2322
| limit | int || 每页数量,默认 10,最大 20 |
2423
| offset | int || 分页偏移量,默认 0 |
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
### 描述
2+
3+
按名称查询指定网关当前各**启用环境**`stage.status = ACTIVE``Release` 引用的资源版本中的资源并集。接口不分页;未匹配的资源名称不会出现在结果中。
4+
5+
接口不按网关状态、网关公开状态、资源公开状态或资源 OAuth2 开关过滤,但仍遵守租户可见性约束。同一资源 ID 出现在多个当前版本时只返回一个快照;先按快照名称精确过滤,再按资源 ID 去重,默认选择版本 ID 较大的快照。
6+
7+
多租户模式下必须通过 `X-Bk-Tenant-Id` 请求头传入当前租户 ID,否则返回 `400`。跨租户访问统一返回 `404`
8+
9+
### 输入参数
10+
11+
#### 路径参数
12+
13+
| 参数名称 | 参数类型 | 必选 | 描述 |
14+
|---|---|---|---|
15+
| gateway_name | string || 网关名称 |
16+
17+
#### 请求参数
18+
19+
| 参数名称 | 参数类型 | 必选 | 描述 |
20+
|---|---|---|---|
21+
| names | string || 资源名称列表,精确匹配,多个以逗号分隔,去重后最多 50 个 |
22+
| fields | string || 返回字段列表,多个以逗号分隔;支持 `id``name``description`,不传返回全部字段 |
23+
24+
### 响应示例
25+
26+
```json
27+
{
28+
"data": [
29+
{
30+
"id": 101,
31+
"name": "get_user",
32+
"description": "查询用户"
33+
}
34+
]
35+
}
36+
```
37+
38+
### 响应参数说明
39+
40+
| 字段 | 类型 | 描述 |
41+
|---|---|---|
42+
| data | array | 匹配的当前已发布资源列表,无分页包装 |
43+
| data[].id | int | 资源 ID |
44+
| data[].name | string | 资源名称 |
45+
| data[].description | string | 当前快照中的资源描述,随请求语言返回中文或英文 |
46+
47+
网关不存在或对当前租户不可见时返回 `404`;网关不存在当前发布版本或名称均未匹配时返回空数组。

src/dashboard/apigateway/apigateway/data/apigw-definitions/bk-apigateway-definition.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ grant_permissions:
135135
- v2_inner_lookup_mcp_servers
136136
- v2_inner_lookup_gateways
137137
- v2_inner_list_gateway_released_resources
138+
- v2_inner_lookup_gateway_released_resources
138139
- v2_inner_list_oauth2_resource_scopes
139140
- v2_inner_list_oauth2_mcp_server_scopes
140141
- v2_open_batch_query_mcp_servers

src/dashboard/apigateway/apigateway/data/apigw-definitions/bk-apigateway-resources.yaml

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5839,12 +5839,6 @@ paths:
58395839
schema:
58405840
type: string
58415841
description: 网关名称
5842-
- name: resource_names
5843-
in: query
5844-
required: false
5845-
schema:
5846-
type: string
5847-
description: 资源名称列表,精确匹配,多个以逗号分隔,最多 50 个
58485842
- name: fields
58495843
in: query
58505844
required: false
@@ -5913,6 +5907,70 @@ paths:
59135907
appVerifiedRequired: true
59145908
resourcePermissionRequired: true
59155909
descriptionEn: List resources referenced by the gateway current releases
5910+
/api/v2/inner/gateways/{gateway_name}/released-resources/-/lookup/:
5911+
get:
5912+
operationId: v2_inner_lookup_gateway_released_resources
5913+
description: 按名称查询网关当前已发布资源,仅统计启用环境(stage.status = ACTIVE)的 Release
5914+
tags:
5915+
- v2_inner
5916+
parameters:
5917+
- name: gateway_name
5918+
in: path
5919+
required: true
5920+
schema:
5921+
type: string
5922+
description: 网关名称
5923+
- name: names
5924+
in: query
5925+
required: true
5926+
schema:
5927+
type: string
5928+
description: 资源名称列表,精确匹配,多个以逗号分隔,最多 50 个
5929+
- name: fields
5930+
in: query
5931+
required: false
5932+
schema:
5933+
type: string
5934+
description: 返回字段列表,多个以逗号分隔;支持 id、name、description
5935+
responses:
5936+
'200':
5937+
description: 成功返回匹配的当前已发布资源列表,无分页包装
5938+
content:
5939+
application/json:
5940+
schema:
5941+
type: object
5942+
properties:
5943+
data:
5944+
type: array
5945+
items:
5946+
type: object
5947+
properties:
5948+
id:
5949+
type: integer
5950+
description: 资源 ID
5951+
name:
5952+
type: string
5953+
description: 资源名称
5954+
description:
5955+
type: string
5956+
description: 资源描述
5957+
x-bk-apigateway-resource:
5958+
isPublic: false
5959+
allowApplyPermission: false
5960+
matchSubpath: false
5961+
enableWebsocket: false
5962+
backend:
5963+
name: default
5964+
method: get
5965+
path: /backend/api/v2/inner/gateways/{gateway_name}/released-resources/-/lookup/
5966+
matchSubpath: false
5967+
timeout: 0
5968+
pluginConfigs: []
5969+
authConfig:
5970+
userVerifiedRequired: false
5971+
appVerifiedRequired: true
5972+
resourcePermissionRequired: true
5973+
descriptionEn: Look up resources referenced by the gateway current releases
59165974
/api/v2/inner/gateways/{gateway_name}/permissions/resources/:
59175975
get:
59185976
operationId: v2_inner_list_gateway_permission_resources

0 commit comments

Comments
 (0)