项目7 · Go 书签与检索服务

用标准库把 HTTP、中间件、存储、并发与优雅退出串成一个完整服务。

约 10 小时
学习重点
  • 标准库 net/http 路由与方法处理
  • 中间件:请求 ID、日志、耗时与 panic 恢复
  • 存储接口与内存实现,错误传播保留上下文
  • context 取消传播与优雅退出
  • 表驱动测试与 httptest 接口测试
页面 / 接口清单
  • 01GET /health 健康检查
  • 02GET /bookmarks?q=&tag=&page=&size= 检索分页
  • 03POST /bookmarks 创建(JSON 校验)
  • 04GET /bookmarks/{id} 与 DELETE /bookmarks/{id}
  • 05请求日志中间件(方法/路径/状态码/耗时/请求 ID)
  • 06SIGINT 优雅退出(停止接收新请求、等待在途请求)
验收清单
0 / 8(0%)

go run . 启动,/health 返回 {status:ok}

POST 校验 url 必填、标题长度;无效 JSON 400;成功 201

q 关键词、tag 过滤、page/size 边界与稳定排序

GET/DELETE 不存在返回 404 与统一错误结构

每个响应带 X-Request-ID,日志包含方法/路径/状态码/耗时

并发读写无数据竞争(并发测试通过)

慢请求在客户端断开后及时结束(context 传递)

go test ./... 全绿,覆盖成功/边界/错误场景

README(项目目录)
# 项目 7:Go 书签与检索服务

用 Go 标准库实现一个完整服务:HTTP 路由、JSON 校验、中间件、存储接口、并发安全、context 取消与优雅退出。

## 启动(参考实现)

```bash
cd examples/projects/p7-go-bookmark/solution
go run .
# 服务在 http://127.0.0.1:8200
curl http://127.0.0.1:8200/health
```

## 测试

```bash
cd examples/projects/p7-go-bookmark/solution
go test ./... -count=1
# ok reactlab.exercise/p7

# 或一键验收(solution 过 / starter 挂):
bash tests/run-checks.sh
```

## 目录

```
starter/   起点(main.go 骨架 + TODO)
solution/  参考实现(main.go / middleware.go / main_test.go)
tests/     验收脚本 run-checks.sh
docs/      api.md · data-model.md(含 SQLite 版本表结构)
fixtures/  bookmarks.json
```

## 接口

见 `docs/api.md`。错误统一为 `{"error":{"category","message"}}`。

## 优雅退出

Ctrl+C 后 `srv.Shutdown` 停止接收新请求并在 5 秒内等待在途请求结束,然后进程退出。
数据模型
Bookmark{ID, Title, URL, Tags []string, CreatedAt time.Time};内存存储 + RWMutex;接口 Store 预留 SQLite 实现位置(docs/data-model.md 给出 SQLite 版本的表结构与迁移说明)。

Command Palette

Search for a command to run...