# Request Validation

## Purpose

定义请求验证规范，覆盖 AI 协议请求（OpenAI、Anthropic）和管理 API 请求的验证规则，确保输入数据的合法性和安全性。

## Requirements

### Requirement: 使用 validator 库

系统 SHALL 使用 go-playground/validator 进行请求验证。

#### Scenario: 验证器初始化

- **WHEN** 应用启动
- **THEN** SHALL 初始化 validator 实例
- **THEN** SHALL 注册自定义验证规则

#### Scenario: 验证规则定义

- **WHEN** 定义请求结构体
- **THEN** SHALL 使用 struct tag 定义验证规则
- **THEN** SHALL 支持必需字段、范围、格式等验证

### Requirement: 验证 OpenAI 请求

系统 SHALL 验证 OpenAI ChatCompletionRequest，验证逻辑位于 ProtocolAdapter 的 decodeRequest 内。

#### Scenario: 必需字段验证

- **WHEN** OpenAI Adapter 的 decodeRequest 解析请求
- **THEN** SHALL 验证 model 字段不为空
- **THEN** SHALL 验证 messages 字段不为空且至少有一条消息
- **THEN** 验证失败 SHALL 返回 INVALID_INPUT 类型的 ConversionError

#### Scenario: 参数范围验证

- **WHEN** OpenAI Adapter 的 decodeRequest 解析参数
- **THEN** SHALL 验证 temperature 范围在 [0, 2]
- **THEN** SHALL 验证 max_tokens 大于 0
- **THEN** SHALL 验证 top_p 范围在 (0, 1]

#### Scenario: 消息内容验证

- **WHEN** 验证 messages 字段
- **THEN** SHALL 验证每条消息的 role 有效（system、developer、user、assistant、tool）
- **THEN** SHALL 验证 content 不为空

### Requirement: 验证 Anthropic 请求

系统 SHALL 验证 Anthropic MessagesRequest，验证逻辑位于 ProtocolAdapter 的 decodeRequest 内。

#### Scenario: 必需字段验证

- **WHEN** Anthropic Adapter 的 decodeRequest 解析请求
- **THEN** SHALL 验证 model 字段不为空
- **THEN** SHALL 验证 messages 字段不为空且至少有一条消息
- **THEN** SHALL 验证 max_tokens 大于 0（或使用默认值）

#### Scenario: 参数范围验证

- **WHEN** Anthropic Adapter 的 decodeRequest 解析参数
- **THEN** SHALL 验证 temperature 范围在 [0, 1]
- **THEN** SHALL 验证 top_p 范围在 (0, 1]

#### Scenario: 消息内容验证

- **WHEN** 验证 messages 字段
- **THEN** SHALL 验证每条消息的 role 有效（user、assistant）
- **THEN** SHALL 验证 content 数组不为空

### Requirement: 验证管理 API 请求

系统 SHALL 验证管理 API 请求。

#### Scenario: Provider 创建验证

- **WHEN** 创建 Provider
- **THEN** SHALL 验证 id、name、api_key、base_url 字段不为空
- **THEN** SHALL 验证 base_url 格式有效（URL 格式）
- **THEN** SHALL 验证 id 格式（字母、数字、下划线、连字符）

#### Scenario: Model 创建验证

- **WHEN** 创建 Model
- **THEN** SHALL 验证 id、provider_id、model_name 字段不为空
- **THEN** SHALL 验证 provider_id 存在

#### Scenario: 更新请求验证

- **WHEN** 更新资源
- **THEN** SHALL 验证至少提供一个可更新字段
- **THEN** SHALL 验证字段值有效性

### Requirement: 供应商 ID 校验

创建供应商时，SHALL 对 `id` 字段进行字符集校验。

#### Scenario: 合法字符集

- **WHEN** 创建供应商，id 仅包含 `[a-zA-Z0-9_]` 字符
- **THEN** SHALL 校验通过

#### Scenario: 非法字符

- **WHEN** 创建供应商，id 包含 `-`、`.`、`/`、空格、中文等非 `[a-zA-Z0-9_]` 字符
- **THEN** SHALL 返回 400 错误

#### Scenario: 长度限制

- **WHEN** 创建供应商，id 长度超过 64
- **THEN** SHALL 返回 400 错误

### Requirement: 模型创建校验

创建模型时，SHALL 对 `provider_id` + `model_name` 进行联合唯一性校验。

#### Scenario: 正常创建

- **WHEN** 创建模型，provider_id 存在且 provider_id + model_name 组合唯一
- **THEN** SHALL 校验通过

#### Scenario: 联合唯一冲突

- **WHEN** 创建模型，provider_id + model_name 组合已存在
- **THEN** SHALL 返回 409 错误

#### Scenario: model_name 为空

- **WHEN** 创建模型，未提供 model_name
- **THEN** SHALL 返回 400 错误

### Requirement: 返回友好的验证错误

系统 SHALL 返回友好的验证错误响应。

#### Scenario: 转换错误格式

- **WHEN** decodeRequest 验证失败返回 ConversionError
- **THEN** ProxyHandler SHALL 使用 clientAdapter.encodeError 编码错误响应
- **THEN** 错误 SHALL 使用客户端协议的格式

#### Scenario: 多字段错误

- **WHEN** 多个字段验证失败
- **THEN** ConversionError.details SHALL 包含所有验证错误
- **THEN** 错误响应 SHALL 包含完整的验证错误信息

### Requirement: 在 handler 中应用验证

系统 SHALL 在 handler 中应用验证。

#### Scenario: 验证中间件

- **WHEN** 使用验证中间件
- **THEN** SHALL 在请求解析后立即验证
- **THEN** SHALL 在验证失败时提前返回错误
- **THEN** SHALL 避免执行后续处理逻辑

#### Scenario: 验证时机

- **WHEN** 处理请求
- **THEN** SHALL 在 handler 函数开始时验证
- **THEN** SHALL 在验证通过后才执行业务逻辑

### Requirement: 使用标准库解析 JSON

系统 SHALL 使用 encoding/json 标准库解析 JSON 请求。

#### Scenario: 提取 model 字段

- **WHEN** 从请求体提取 model 字段
- **THEN** SHALL 使用 json.Unmarshal 解析到结构体
- **THEN** SHALL NOT 手动扫描字节查找字段
- **THEN** 解析失败 SHALL 返回空字符串（不报错）

#### Scenario: 检测 stream 字段

- **WHEN** 检测请求是否为流式请求
- **THEN** SHALL 使用 json.Unmarshal 解析到结构体
- **THEN** SHALL NOT 手动扫描字节查找字段
- **THEN** 解析失败 SHALL 返回 false（非流式）

#### Scenario: JSON 解析健壮性

- **WHEN** 解析 JSON 请求体
- **THEN** SHALL 正确处理转义字符
- **THEN** SHALL 正确处理嵌套结构
- **THEN** SHALL 正确处理 Unicode 字符
- **THEN** 解析失败 SHALL 有明确的错误处理
