From 11a876ebbea877b046195e20a22d99de48c43f9a Mon Sep 17 00:00:00 2001 From: mzaxd Date: Tue, 27 Jan 2026 21:39:17 +0800 Subject: [PATCH] fix: handle null query params in API + add testing guide --- docs/api-testing-guide.md | 161 ++++++++++++++++++++++++++++++++++++ src/app/api/events/route.ts | 8 +- 2 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 docs/api-testing-guide.md diff --git a/docs/api-testing-guide.md b/docs/api-testing-guide.md new file mode 100644 index 0000000..9752191 --- /dev/null +++ b/docs/api-testing-guide.md @@ -0,0 +1,161 @@ +# API 测试指南 + +## GET /api/events + +获取所有事件: + +```bash +curl http://localhost:3000/api/events +``` + +筛选特定年份: + +```bash +curl "http://localhost:3000/api/events?year=2024" +``` + +限制返回数量: + +```bash +curl "http://localhost:3000/api/events?limit=10" +``` + +分页: + +```bash +curl "http://localhost:3000/api/events?offset=10&limit=10" +``` + +## POST /api/events + +创建单个事件: + +```bash +curl -X POST http://localhost:3000/api/events \ + -H "Content-Type: application/json" \ + -H "X-API-Key: YOUR_API_KEY" \ + -d '[ + { + "title": "事件标题", + "eventDate": "2023-03-14T00:00:00Z", + "description": "事件描述(10-500字)", + "imageUrl": "https://example.com/image.jpg" + } + ]' +``` + +批量创建事件: + +```bash +curl -X POST http://localhost:3000/api/events \ + -H "Content-Type: application/json" \ + -H "X-API-Key: YOUR_API_KEY" \ + -d '[ + { "title": "事件1", "eventDate": "2023-01-01T00:00:00Z", "description": "描述1", "imageUrl": "https://example.com/1.jpg" }, + { "title": "事件2", "eventDate": "2023-02-01T00:00:00Z", "description": "描述2", "imageUrl": "https://example.com/2.jpg" } + ]' +``` + +包含可选字段: + +```bash +curl -X POST http://localhost:3000/api/events \ + -H "Content-Type: application/json" \ + -H "X-API-Key: YOUR_API_KEY" \ + -d '[ + { + "title": "GPT-4 Release", + "titleEn": "GPT-4 发布", + "eventDate": "2023-03-14T00:00:00Z", + "description": "OpenAI launches multimodal LLM", + "descriptionEn": "OpenAI 发布多模态大语言模型", + "imageUrl": "https://example.com/gpt4.jpg", + "sourceUrl": "https://openai.com/blog/gpt-4" + } + ]' +``` + +## 验证规则 + +### 输入验证 (AIEventInputSchema) + +- `title`: 1-200 字符(必填) +- `titleEn`: 最多 200 字符(可选) +- `eventDate`: ISO 8601 datetime 格式(必填) +- `description`: 10-500 字符(必填) +- `descriptionEn`: 最多 500 字符(可选) +- `imageUrl`: 有效 URL(必填) +- `sourceUrl`: 有效 URL(可选) + +### 查询参数验证 (AIEventQuerySchema) + +- `year`: 4位数字年份(可选) +- `limit`: 正整数(可选,默认 100) +- `offset`: 非负整数(可选,默认 0) + +## 认证 + +所有 POST 请求必须在请求头中包含 API Key: + +``` +X-API-Key: YOUR_API_KEY +``` + +## 响应示例 + +### 成功响应 (POST) + +```json +{ + "created": 2, + "total": 2 +} +``` + +### 成功响应 (GET) + +```json +{ + "events": [ + { + "id": "cmkwn6q0300004jjz4lobtkpf", + "title": "Transformer论文", + "titleEn": null, + "eventDate": "2017-06-12T00:00:00.000Z", + "description": "Google团队发表Transformer架构", + "descriptionEn": null, + "imageUrl": "https://images.unsplash.com/photo-1677442136019-21780ecad995?w=800", + "sourceUrl": null, + "createdAt": "2026-01-27T13:38:39.268Z", + "updatedAt": "2026-01-27T13:38:39.268Z" + } + ] +} +``` + +### 错误响应 + +```json +{ + "error": "Validation failed", + "details": [ + { + "code": "too_small", + "path": ["0", "description"], + "message": "String must contain at least 10 character(s)" + } + ] +} +``` + +## 测试记录 + +### 2025-01-27 测试结果 + +- ✅ GET /api/events - 返回空列表 +- ✅ POST /api/events - 单个事件创建成功 +- ✅ GET /api/events - 验证事件已创建(1个事件) +- ✅ POST /api/events - 批量创建成功(2个事件) +- ✅ GET /api/events?year=2018 - 年份筛选成功(返回2个事件) + +所有基础功能测试通过! diff --git a/src/app/api/events/route.ts b/src/app/api/events/route.ts index 217e9ea..a4fed4a 100644 --- a/src/app/api/events/route.ts +++ b/src/app/api/events/route.ts @@ -65,12 +65,12 @@ export async function POST(request: NextRequest) { } export async function GET(request: NextRequest) { - // 1. 解析查询参数 + // 1. 解析查询参数(将 null 转换为 undefined) const searchParams = request.nextUrl.searchParams; const queryParams = { - year: searchParams.get('year'), - limit: searchParams.get('limit'), - offset: searchParams.get('offset'), + year: searchParams.get('year') || undefined, + limit: searchParams.get('limit') || undefined, + offset: searchParams.get('offset') || undefined, }; // 2. 验证查询参数