tidbrest · 公共 Data API —— 真实 TiDB Cloud Starter E2E

每条用例 = 一对"请求↔响应"(Postman 风格)。后端: cmd/tidbrest dev 模式打 app_e2e(真库)。无脱敏(一次性测试库)。
11
用例
11
符合预期
0
偏离
面 A·Data
GET/schema2001ms
📋 只暴露 tasks/comments,私表不出现 (期望 200)
响应头
Content-Type: application/json
X-Request-Id: claude.sharedjDIpPaxMHm-000035
响应体
{"data":{"functions":[],"procedures":[],"published_resources":[{"logical_table":"comments","isolation_mode":"","allowed_actions":["schema.read","table.read","table.count","table.insert","table.upsert","table.update","table.delete"],"allowed_columns":["author","body","created_at","id","is_internal","task_id"]},{"logical_table":"tasks","isolation_mode":"","allowed_actions":["schema.read","table.read","table.count","table.insert","table.upsert","table.update","table.delete"],"allowed_columns":["created_at","id","owner","priority","status","title","updated_at"]}],"tables":[{"name":"comments","type":"table","columns":[{"name":"id","position":1,"db_type":"bigint","go_type":"int64","json_type":"integer","nullable":false,"is_primary_key":true,"is_auto_increment":true,"is_unique":true},{"name":"task_id","position":2,"db_type":"bigint","go_type":"int64","json_type":"integer","nullable":false,"is_primary_key":false,"is_auto_increment":false,"is_unique":false},{"name":"body","position":3,"db_type":"text","go_type":"string","json_type":"string","nullable":false,"max_length":65535,"is_primary_key":false,"is_auto_increment":false,"is_unique":false},{"name":"author","position":4,"db_type":"varchar(128)","go_type":"string","json_type":"string","nullable":false,"max_length":128,"is_primary_key":false,"is_auto_increment":false,"is_unique":false},{"name":"is_internal","position":5,"db_type":"tinyint(1)","go_type":"bool","json_type":"boolean","nullable":false,"default":"0","is_primary_key":false,"is_auto_increment":false,"is_unique":false},{"name":"created_at","position":6,"db_type":"timestamp","go_type":"time.Time","json_type":"string(date-time)","nullable":false,"default":"CURRENT_TIMESTAMP","is_primary_key":false,"is_auto_increment":false,"is_unique":false}],"primary_key":["id"],"foreign_keys":null,"indexes":[{"name":"idx_comments_1","columns":["author"],"is_unique":false},{"name":"idx_comments_2","columns":["task_id"],"is_unique":false}],"row_count":3},{"name":"tasks","type":"table","columns":[{"name":"id","position":1,"db_type":"bigint","go_type":"int64","json_type":"integer","nullable":false,"is_primary_key":true,"is_auto_increment":true,"is_unique":true},{"name":"title","position":2,"db_type":"varchar(255)","go_type":"string","json_type":"string","nullable":false,"max_length":255,"is_primary_key":false,"is_auto_increment":false,"is_unique":true},{"name":"status","position":3,"db_type":"varchar(32)","go_type":"string","json_type":"string","nullable":false,"default":"todo","max_length":32,"is_primary_key":false,"is_auto_increment":false,"is_unique":false},{"name":"priority","position":4,"db_type":"int","go_type":"int32","json_type":"integer","nullable":false,"default":"0","is_primary_key":false,"is_auto_increment":false,"is_unique":false},{"name":"owner","position":5,"db_type":"varchar(128)","go_type":"string","json_type":"string","nullable":false,"default":"unassigned","max_length":128,"is_primary_key":false,"is_auto_increment":false,"is_unique":false},{"name":"created_at","position":6,"db_type":"timestamp","go_type":"time.Time","json_type":"string(date-time)","nullable":false,"default":"CURRENT_TIMESTAMP","is_primary_key":false,"is_auto_increment":false,"is_unique":false},{"name":"updated_at","position":7,"db_type":"timestamp","go_type":"time.Time","json_type":"string(date-time)","nullable":false,"default":"CURRENT_TIMESTAMP","is_primary_key":false,"is_auto_increment":false,"is_unique":false}],"primary_key":["id"],"foreign_keys":null,"indexes":[{"name":"idx_tasks_1","columns":["status","priority"],"is_unique":false},{"name":"idx_tasks_2","columns":["title"],"is_unique":true}],"row_count":3}],"views":[]}}
GET/doc2000ms
📋 只为已发布表生成路径 (期望 200)
响应头
Content-Type: application/json
X-Request-Id: claude.sharedjDIpPaxMHm-000036
响应体
{"components":{"schemas":{"Error":{"properties":{"code":{"type":"string"},"details":{"description":"Optional stable diagnostic details. For schema_drift this contains redacted logical resource, column, expected/actual summary, remediation, and no physical table names or sensitive values.","type":"object"},"message":{"type":"string"},"request_id":{"description":"Request identifier also returned in the X-Request-ID response header.","type":"string"},"status":{"type":"integer"},"version":{"const":"tidbrest.error.v1","type":"string"}},"required":["version","code","message","status"],"type":"object"},"ErrorResponse":{"properties":{"error":{"$ref":"#/components/schemas/Error"}},"required":["error"],"type":"object"},"table_comments":{"properties":{"author":{"description":"varchar(128)","nullable":false,"type":"string"},"body":{"description":"text","nullable":false,"type":"string"},"created_at":{"description":"timestamp","nullable":false,"type":"string"},"id":{"description":"bigint","nullable":false,"type":"integer"},"is_internal":{"description":"tinyint(1)","nullable":false,"type":"boolean"},"task_id":{"description":"bigint","nullable":false,"type":"integer"}},"type":"object"},"table_comments_insert":{"properties":{"author":{"description":"varchar(128)","nullable":false,"type":"string"},"body":{"description":"text","nullable":false,"type":"string"},"created_at":{"description":"timestamp","nullable":false,"type":"string"},"is_internal":{"description":"tinyint(1)","nullable":false,"type":"boolean"},"task_id":{"description":"bigint","nullable":false,"type":"integer"}},"required":["task_id","body","author"],"type":"object"},"table_comments_update":{"properties":{"author":{"description":"varchar(128)","nullable":false,"type":"string"},"body":{"description":"text","nullable":false,"type":"string"},"created_at":{"description":"timestamp","nullable":false,"type":"string"},"is_internal":{"description":"tinyint(1)","nullable":false,"type":"boolean"},"task_id":{"description":"bigint","nullable":false,"type":"integer"}},"type":"object"},"table_tasks":{"properties":{"created_at":{"description":"timestamp","nullable":false,"type":"string"},"id":{"description":"bigint","nullable":false,"type":"integer"},"owner":{"description":"varchar(128)","nullable":false,"type":"string"},"priority":{"description":"int","nullable":false,"type":"integer"},"status":{"description":"varchar(32)","nullable":false,"type":"string"},"title":{"description":"varchar(255)","nullable":false,"type":"string"},"updated_at":{"description":"timestamp","nullable":false,"type":"string"}},"type":"object"},"table_tasks_insert":{"properties":{"created_at":{"description":"timestamp","nullable":false,"type":"string"},"owner":{"description":"varchar(128)","nullable":false,"type":"string"},"priority":{"description":"int","nullable":false,"type":"integer"},"status":{"description":"varchar(32)","nullable":false,"type":"string"},"title":{"description":"varchar(255)","nullable":false,"type":"string"},"updated_at":{"description":"timestamp","nullable":false,"type":"string"}},"required":["title"],"type":"object"},"table_tasks_update":{"properties":{"created_at":{"description":"timestamp","nullable":false,"type":"string"},"owner":{"description":"varchar(128)","nullable":false,"type":"string"},"priority":{"description":"int","nullable":false,"type":"integer"},"status":{"description":"varchar(32)","nullable":false,"type":"string"},"title":{"description":"varchar(255)","nullable":false,"type":"string"},"updated_at":{"description":"timestamp","nullable":false,"type":"string"}},"type":"object"}}},"info":{"description":"Minimal Faucet-derived REST API generated from published TiDB schema metadata.","title":"TiDB Schema REST MVP","version":"tidbrest.contract.v1"},"openapi":"3.1.0","paths":{"/doc":{"get":{"responses":{"200":{"description":"OpenAPI document"}},"summary":"Get OpenAPI document","tags":["Console Discovery API"],"x-tidbrest-audience":"console_discovery_api"}},"/schema":{"get":{"responses":{"200":{"description":"Published schema"}},"summary":"List published schema","tags":["Console Discovery API"],"x-tidbrest-audience":"console_discovery_api"}},"/schema/comments":{"get":{"responses":{"200":{"description":"Table schema"}},"summary":"Get comments schema","tags":["Console Discovery API"],"x-tidbrest-audience":"console_discovery_api"}},"/schema/tasks":{"get":{"responses":{"200":{"description":"Table schema"}},"summary":"Get tasks schema","tags":["Console Discovery API"],"x-tidbrest-audience":"console_discovery_api"}},"/table/comments":{"delete":{"parameters":[{"description":"Column filter for id, for example id=eq.value","in":"query","name":"id","required":false,"schema":{"type":"string"}},{"description":"Column filter for task_id, for example task_id=eq.value","in":"query","name":"task_id","required":false,"schema":{"type":"string"}},{"description":"Column filter for body, for example body=eq.value","in":"query","name":"body","required":false,"schema":{"type":"string"}},{"description":"Column filter for author, for example author=eq.value","in":"query","name":"author","required":false,"schema":{"type":"string"}},{"description":"Column filter for is_internal, for example is_internal=eq.value","in":"query","name":"is_internal","required":false,"schema":{"type":"string"}},{"description":"Column filter for created_at, for example created_at=eq.value","in":"query","name":"created_at","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Rows affected"}},"summary":"Delete comments","tags":["Public Data API"],"x-tidbrest-audience":"public_data_api","x-tidbrest-route-status":"canonical_project_data_api"},"get":{"parameters":[{"description":"Comma-separated column list","in":"query","name":"select","required":false,"schema":{"type":"string"}},{"description":"Sort expression, for example created_at.desc. Allowed order columns: author, body, created_at, id, is_internal, task_id","in":"query","name":"order","required":false,"schema":{"type":"string"}},{"description":"Maximum number of rows","in":"query","name":"limit","required":false,"schema":{"type":"string"}},{"description":"Rows to skip","in":"query","name":"offset","required":false,"schema":{"type":"string"}},{"description":"Use count=exact to include exact total count metadata","in":"query","name":"count","required":false,"schema":{"type":"string"}},{"description":"Item range header using items=start-end","in":"header","name":"Range","required":false,"schema":{"type":"string"}},{"description":"AND-only predicate expression. OR, NOT, parentheses, joins, qualified columns, functions, casts, JSON paths, aggregates, and raw SQL are unsupported.","in":"query","name":"filter","required":false,"schema":{"type":"string"}},{"description":"Column filter for id, for example id=eq.value","in":"query","name":"id","required":false,"schema":{"type":"string"}},{"description":"Column filter for task_id, for example task_id=eq.value","in":"query","name":"task_id","required":false,"schema":{"type":"string"}},{"description":"Column filter for body, for example body=eq.value","in":"query","name":"body","required":false,"schema":{"type":"string"}},{"description":"Column filter for author, for example author=eq.value","in":"query","name":"author","required":false,"schema":{"type":"string"}},{"description":"Column filter for is_internal, for example is_internal=eq.value","in":"query","name":"is_internal","required":false,"schema":{"type":"string"}},{"description":"Column filter for created_at, for example created_at=eq.value","in":"query","name":"created_at","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/table_comments"},"type":"array"}},"type":"object"}},"application/x-ndjson":{"schema":{"description":"Newline-delimited JSON; each line is one row object using the same selected columns as application/json.","type":"string"}}},"description":"Success"}},"summary":"Query comments","tags":["Public Data API"],"x-tidbrest-audience":"public_data_api","x-tidbrest-route-status":"canonical_project_data_api"},"patch":{"operationId":"update_comments","
GET/table/tasks?limit=3&order=id.desc2003823ms
📋 读回真实库行 (期望 200)
响应头
Content-Type: application/json
X-Request-Id: claude.sharedjDIpPaxMHm-000037
响应体
{"data":[{"created_at":"2026-06-29T20:56:53Z","id":128,"owner":"qa","priority":124,"status":"todo","title":"bulk-task-124","updated_at":"2026-06-29T20:56:53Z"},{"created_at":"2026-06-29T20:56:53Z","id":127,"owner":"qa","priority":123,"status":"todo","title":"bulk-task-123","updated_at":"2026-06-29T20:56:53Z"},{"created_at":"2026-06-29T20:56:52Z","id":126,"owner":"qa","priority":122,"status":"todo","title":"bulk-task-122","updated_at":"2026-06-29T20:56:52Z"}],"meta":{"count":3,"limit":3,"offset":0}}
GET/table/tasks?status=eq.done&select=id,title,status200885ms
📋 eq 过滤 + select 投影生效 (期望 200)
响应头
Content-Type: application/json
X-Request-Id: claude.sharedjDIpPaxMHm-000038
响应体
{"data":[{"id":3,"status":"done","title":"Review OpenAPI"}],"meta":{"count":1,"limit":25,"offset":0}}
POST/table/tasks201879ms
📋 真实写入 TiDB,rows_affected=1 (期望 200/201)
请求体
{"title":"report task 215953.172","status":"todo","priority":5,"owner":"report"}
响应头
Content-Type: application/json
X-Request-Id: claude.sharedjDIpPaxMHm-000039
响应体
{"data":[{"owner":"report","priority":5,"status":"todo","title":"report task 215953.172"}],"meta":{"rows_affected":1}}
PATCH/table/tasks?title=eq.report%20task%20215953.172200887ms
📋 用可写列过滤更新→成功 (期望 200)
请求体
{"status":"done","priority":9}
响应头
Content-Type: application/json
X-Request-Id: claude.sharedjDIpPaxMHm-000040
响应体
{"data":{"rows_affected":1}}
PATCH/table/tasks?id=eq.14030ms
📋 真实发现:用主键 id 过滤更新被策略拒(id 不在 update 允许列) (期望 403 policy_denied(发现))
请求体
{"status":"done"}
响应头
Content-Type: application/json
X-Request-Id: claude.sharedjDIpPaxMHm-000041
响应体
{"error":{"code":"policy_denied","message":"policy denied column \"id\" for action \"table.update\" on table \"tasks\"","request_id":"claude.sharedjDIpPaxMHm-000041","status":403,"version":"tidbrest.error.v1"}}
DELETE/table/tasks?title=eq.report%20task%20215953.172200897ms
📋 清理插入行→成功 (期望 200)
响应头
Content-Type: application/json
X-Request-Id: claude.sharedjDIpPaxMHm-000042
响应体
{"data":{"rows_affected":1}}
GET/table/private_notes4030ms
📋 private_notes 不可访问 (期望 403/404)
响应头
Content-Type: application/json
X-Request-Id: claude.sharedjDIpPaxMHm-000043
响应体
{"error":{"code":"table_not_published","message":"table \"private_notes\" is not published","request_id":"claude.sharedjDIpPaxMHm-000043","status":403,"version":"tidbrest.error.v1"}}
POST/sql5010ms
📋 /sql 不存在(只暴露受控 REST) (期望 404/501)
请求体
{"q":"select 1"}
响应头
Content-Type: application/json
X-Request-Id: claude.sharedjDIpPaxMHm-000044
响应体
{"error":{"code":"unsupported_operation","message":"raw SQL is not part of the public TiDB Data API","request_id":"claude.sharedjDIpPaxMHm-000044","status":501,"version":"tidbrest.error.v1"}}
GET/table/tasks?title=eq.x%27%20OR%20%271%27%3D%2712001056ms
📋 title=eq.x' OR '1'='1 当字面值,不破坏 SQL (期望 200(0 行))
响应头
Content-Type: application/json
X-Request-Id: claude.sharedjDIpPaxMHm-000045
响应体
{"data":[],"meta":{"count":0,"limit":25,"offset":0}}