compliance/memory-bank/response_adaptation_layer_design.md
2025-06-27 18:26:20 +08:00

113 lines
6.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 设计文档:响应适配层 (Response Adaptation Layer)
## 1. 问题背景
在对企业内部大量存量的API进行合规性测试时我们遇到了一个常见的挑战API的设计风格存在不一致性。具体表现为
1. **响应体结构不统一**
* 部分API遵循标准的包装格式`{"code": 0, "message": "success", "data": {...}}`,真正的业务数据位于 `data` 字段内。
* 另一部分API则直接返回业务数据对象`{...}`
* 当返回列表时,业务数据可能是 `data: [...]`,也可能是直接返回 `[...]`
2. **数据模型Schema来源不统一**
* 标准的API会在其OpenAPI/Swagger规范中直接定义响应体的Schema。
* 但存在一类特殊的"核心模型"API其响应数据对应的Schema需要通过调用另一个独立的API端点来动态获取。
这些不一致性给自动化的Schema验证带来了极大的困难。如果为每种情况都编写一个独立的测试用例会导致代码大量冗余且难以维护。
## 2. 核心理念与设计目标
为了优雅地解决上述问题,我们引入 **"响应适配层" (Response Adaptation Layer)** 的概念。
其核心理念是将 **"适配"** 过程如何找到真正需要验证的数据和其对应的Schema与核心的 **"验证"** 逻辑数据是否符合Schema的规范完全解耦。
**设计目标**
* **灵活性与可扩展性**能够轻松适应未来可能出现的更多样的API风格只需增加新的适配策略而无需修改核心验证框架。
* **高内聚,低耦合**:将适配逻辑集中处理,保持核心验证测试用例的纯净和通用。
* **配置驱动**:适配规则应通过外部配置来定义,而非硬编码在代码中。
## 3. 架构设计
响应适配层位于 "API调用" 和 "测试断言" 之间。它接收原始的HTTP响应和API端点信息输出归一化后的数据和Schema供下游的验证引擎使用。
```mermaid
flowchart TD
subgraph 测试执行流程
A[调用API获取响应] --> B{响应适配层};
subgraph B
C[响应数据提取器]
D[动态Schema提供者]
end
B --> E[归一化的数据和Schema];
E --> F[执行Schema验证];
end
```
## 4. 核心组件详述
### 4.1. 响应数据提取器 (Response Data Extractor)
这是一个工具模块,提供一个核心函数 `extract_data_for_validation(response_json)`负责从原始API响应中智能地提取出需要被验证的核心业务数据。
**提取策略**
1. **检查标准包装**:检查响应体 `response_json` 是否同时包含 `code``data` 字段。
* **是**:返回 `response_json['data']` 的内容作为待处理数据。
* **否**:返回整个 `response_json` 作为待处理数据。
2. **处理列表与对象**:对上一步获取的待处理数据进行检查。
* **是列表 (List)**
* 如果列表为空 `[]`则认为无法进行Schema验证直接返回 `None`,跳过验证。
* 如果列表非空,则返回列表的第一个元素 `list[0]` 作为最终需要验证的数据。这是基于"一个列表内的所有元素都应遵循相同Schema"的假设。
* **是对象 (Dict)**:直接返回该对象作为最终需要验证的数据。
### 4.2. 动态Schema提供者 (Dynamic Schema Provider)
这是一个独立的模块负责根据API端点信息为其提供正确的JSON Schema特别是在Schema需要从外部动态获取的场景下。
**工作机制**
1. **配置驱动**:在测试项目的配置文件中,增加一个映射关系表 `dynamic_schema_mapping`用于定义哪个API端点或哪种模式的API的Schema需要从哪个URL获取。
*示例配置 (config.yaml)*:
```yaml
dynamic_schema_mapping:
# key可以是精确路径也可以是正则表达式
"/api/v1/core-models/get/{model_id}": "https://api.internal/schemas/{model_id}"
"/api/v2/special-data/.*": "https://api.internal/schemas/special-data.json"
```
2. **按需获取**: 当测试用例需要Schema时提供者会检查当前测试的API端点是否在 `dynamic_schema_mapping` 中有匹配项。
* **有匹配**: 根据配置的URL模板例如从路径中提取 `model_id`构造完整的Schema URL然后发起HTTP GET请求获取Schema内容。
* **无匹配**: 回退到默认行为即从当前API的OpenAPI规范中查找其定义的响应Schema。
3. **缓存机制**: 为了避免对同一个Schema URL的重复网络请求提供者内部会维护一个缓存如一个简单的字典。在发起请求前会先检查缓存中是否已有该URL的Schema。
## 5. 整合与实现
我们将创建一个新的、高度灵活的测试用例 `FlexibleSchemaValidationCase` 来整合上述两个组件。
**实现步骤**
1. **测试用例识别**: 在 `applies_to` 方法中定义此测试用例适用于哪些API。我们可以通过在OpenAPI规范中使用一个自定义扩展字段 `x-flexible-validation: true` 来标记目标API。
*示例 (openapi.yaml)*:
```yaml
paths:
/api/v1/core-models/get/{model_id}:
get:
summary: "获取核心模型数据"
x-flexible-validation: true # 标记适用此测试用例
...
```
2. **执行逻辑 (`execute` 方法)**:
a. 调用 **动态Schema提供者**传入当前端点信息获取对应的JSON Schema。如果获取失败则测试用例断言失败。
b. 正常调用该API获得HTTP响应。
c. 将响应体JSON传递给 **响应数据提取器**,获取归一化后的核心业务数据。如果返回`None`(例如空列表),则该测试用例标记为 `SKIPPED`。
d. 使用标准的 `jsonschema.validate` 函数用步骤a获取的Schema来验证步骤c提取的数据。
e. 根据验证结果,断言测试成功或失败。
## 6. 方案优势总结
* **关注点分离**:将复杂的适配逻辑与核心的验证逻辑解耦,代码更清晰,可维护性更高。
* **高度可扩展**未来若有新的API风格只需在"提取器"或"提供者"中增加新策略,而无需改动大量测试用例。
* **配置灵活**通过外部配置文件和API规范中的自定义字段来驱动适应性强无需硬编码。
* **代码复用**:将通用的适配逻辑沉淀到工具库中,避免在不同测试用例中重复实现。